]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: htx: Fix the position returned by htx_defrag()
authorChristopher Faulet <cfaulet@haproxy.com>
Fri, 18 Sep 2026 11:20:09 +0000 (13:20 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 18 Sep 2026 15:05:18 +0000 (17:05 +0200)
In htx_defrag(), the <new> 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 <new> 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
<new> 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.

src/htx.c

index 1ff7ccce8737d5f11a8b3fb9c4ff063e8cdb66c3..5dcd433ad41c76d7a4954085807d0fef50b5332e 100644 (file)
--- 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 <blk> is defined, save its new position */
                if (blk == oldblk)
-                       blkpos = new;
-
-               new++;
+                       blkpos = htx_get_blk_pos(tmp, newblk);
        }
 
        htx->data = tmp->data;