BUG/MEDIUM: htx: Don't crush blocks payload when append is done on a data block

If there is a data block when a header block is added in a HTX message, its
payload will be inserted after the data block payload. But its index will be
moved before the EOH block. So at this stage, if a new data block is added, we
will try to append its payload to the last data block (because it is also the
tail). Thus the payload of the further header block will be crushed.

This cannot happens if the payloads wrap thanks to the previous fix. But it
happens when the tail is not the front too. So now, in this case, we add a new
block instead of appending.

This patch must be backported in 1.9.
This commit is contained in:
Christopher Faulet 2019-04-10 14:54:46 +02:00
parent 05aab64b06
commit f1449b785e

View File

@ -353,8 +353,9 @@ struct htx_ret htx_drain(struct htx *htx, uint32_t count)
static struct htx_blk *htx_append_blk_value(struct htx *htx, enum htx_blk_type type, static struct htx_blk *htx_append_blk_value(struct htx *htx, enum htx_blk_type type,
const struct ist data) const struct ist data)
{ {
struct htx_blk *blk; struct htx_blk *blk, *tailblk, *headblk, *frtblk;
struct ist v; struct ist v;
int32_t room;
if (!htx->used) if (!htx->used)
goto add_new_block; goto add_new_block;
@ -367,47 +368,45 @@ static struct htx_blk *htx_append_blk_value(struct htx *htx, enum htx_blk_type t
if (type != HTX_BLK_DATA && type != HTX_BLK_TLR) if (type != HTX_BLK_DATA && type != HTX_BLK_TLR)
goto add_new_block; goto add_new_block;
/* get the tail block */ /* get the tail and head block */
blk = htx_get_blk(htx, htx->tail); tailblk = htx_get_tail_blk(htx);
headblk = htx_get_head_blk(htx);
if (tailblk == NULL || headblk == NULL)
goto add_new_block;
/* Don't try to append data if the last inserted block is not of the /* Don't try to append data if the last inserted block is not of the
* same type */ * same type */
if (type != htx_get_blk_type(blk)) if (type != htx_get_blk_type(tailblk))
goto add_new_block; goto add_new_block;
/* /*
* Same type and enough space: append data * Same type and enough space: append data
*/ */
if (htx->tail + 1 == htx->wrap) { frtblk = htx_get_blk(htx, htx->front);
struct htx_blk *frtblk = htx_get_blk(htx, htx->front); if (tailblk->addr >= headblk->addr) {
int32_t tailroom = sizeof(htx->blocks[0]) * htx_pos_to_idx(htx, htx->tail) - (frtblk->addr + htx_get_blksz(frtblk)); if (htx->tail != htx->front)
if (tailroom >= (int32_t)data.len) goto add_new_block;
goto append_data; room = sizeof(htx->blocks[0]) * htx_pos_to_idx(htx, htx->tail) - (frtblk->addr + htx_get_blksz(frtblk));
htx_defrag(htx, NULL);
blk = htx_get_blk(htx, htx->tail);
}
else {
struct htx_blk *headblk = htx_get_blk(htx, htx_get_head(htx));
int32_t headroom = headblk->addr - (blk->addr + htx_get_blksz(blk));
if (headroom >= (int32_t)data.len)
goto append_data;
htx_defrag(htx, NULL);
blk = htx_get_blk(htx, htx->tail);
} }
else
room = headblk->addr - (tailblk->addr + htx_get_blksz(tailblk));
if (room < (int32_t)data.len)
tailblk = htx_defrag(htx, tailblk);
append_data: append_data:
/* get the value of the tail block */ /* get the value of the tail block */
/* FIXME: check v.len + data.len < 256MB */ /* FIXME: check v.len + data.len < 256MB */
v = htx_get_blk_value(htx, blk); v = htx_get_blk_value(htx, tailblk);
/* Append data and update the block itself */ /* Append data and update the block itself */
memcpy(v.ptr + v.len, data.ptr, data.len); memcpy(v.ptr + v.len, data.ptr, data.len);
htx_set_blk_value_len(blk, v.len + data.len); htx_set_blk_value_len(tailblk, v.len + data.len);
/* Update HTTP message */ /* Update HTTP message */
htx->data += data.len; htx->data += data.len;
return blk; return tailblk;
add_new_block: add_new_block:
/* FIXME: check tlr.len (< 256MB) */ /* FIXME: check tlr.len (< 256MB) */