From: Christopher Faulet Date: Fri, 18 Sep 2026 11:20:09 +0000 (+0200) Subject: BUG/MEDIUM: htx: Fix the position returned by htx_defrag() X-Git-Tag: v3.5-dev8~179 X-Git-Url: https://git.kaiwu.me/$%7BGITURL%7D$%7Bcid%7D?a=commitdiff_plain;h=b38f5605d3a37d495d1b7ca4edecd67c2d7cff4b;p=haproxy.git BUG/MEDIUM: htx: Fix the position returned by htx_defrag() In htx_defrag(), the counter was used to compute the new position of the start-line and of the referenced block, if any. But this counter was incremented for each block of the source message while consecutive DATA blocks may be merged when they are copied. In this case, no new block is created in the temporary message, so was desynchronized from the real position. As a consequence, htx_defrag() could return a block located after the tail of the message, thus pointing on the payload part instead of a block descriptor. The caller then used it to copy data, at a pseudo-random offset, corrupting the message. htx_replace_blk_value() is the only concerned caller because it is the only one referencing a block that may be a DATA block. htx_replace_header() and htx_replace_stline() reference a header or a start-line, always located before any DATA block. So, to trigger the bug, an expansion requiring a defragmentation must be performed on a DATA block preceded by at least two mergeable DATA blocks. The positions are now computed from the block really created or updated. The counter is thus no longer necessary and was removed. The flaw exists since the HTX was introduced. However the only known way to expand a DATA block this way is the decompression filter, added in 3.5-dev. So no released version should be affected. This patch may be backported to all stable versions as a precaution. --- diff --git a/src/htx.c b/src/htx.c index 1ff7ccce8..5dcd433ad 100644 --- a/src/htx.c +++ b/src/htx.c @@ -52,7 +52,7 @@ struct htx_blk *htx_defrag(struct htx *htx, struct htx_blk *blk, uint32_t blkinf struct htx *tmp = htxbuf(chunk); struct htx_blk *newblk, *oldblk; enum htx_blk_type type; - uint32_t new, old, blkpos; + uint32_t old, blkpos; uint32_t blksz; if (htx->head == -1) @@ -60,7 +60,6 @@ struct htx_blk *htx_defrag(struct htx *htx, struct htx_blk *blk, uint32_t blkinf blkpos = -1; - new = 0; tmp->size = htx->size; tmp->data = 0; @@ -94,13 +93,11 @@ struct htx_blk *htx_defrag(struct htx *htx, struct htx_blk *blk, uint32_t blkinf /* update the start-line position */ if (htx->first == old) - tmp->first = new; + tmp->first = htx_get_blk_pos(tmp, newblk); /* if is defined, save its new position */ if (blk == oldblk) - blkpos = new; - - new++; + blkpos = htx_get_blk_pos(tmp, newblk); } htx->data = tmp->data;