]> git.kaiwu.me - haproxy.git/commitdiff
MEDIUM: htx: Be sure size of headers never exceed regular buffer on update
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 29 Jun 2026 16:33:02 +0000 (18:33 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 8 Jul 2026 06:52:06 +0000 (08:52 +0200)
When an HTX header or an HTX start-line is added or updated, a test is now
performed to be sure the whole headers size, including the start-line never
exceeds the regular buffer size. It is mandatory because it is now possible
to use larger buffers. However, it remains impossible to send HEADERS frame
in H2 and QUIC larger than a regular buffer. So we must be sure the HTTP
analysis will never produce too big headers because they will be rejected
later, at the forwarding stage. The purpose of large buffers is to be able
to store large payload, larger than regular buffers. Headers must remain
quite small.

This commit depends on the following one:

  MINOR: htx: Add a field to save the headers data size

Both should be backported to 3.4 to avoid any trouble with large buffers. It
is not strictly speaking a bug, but it will avoid hazardous behavior
depending on the payload size.

src/htx.c

index 132c2c1216d873ed7832ba55150527c3b0599be2..7143e396156a4157c220da448df59797538ff344 100644 (file)
--- a/src/htx.c
+++ b/src/htx.c
@@ -29,6 +29,14 @@ static inline __attribute__((always_inline)) void htx_memcpy(void *dst, void *sr
                memcpy(dst, src, len);
 }
 
+/* Retruns 1 if the headers size with addition of <len> exceeds the maximum size
+ * allowed for headers.
+ */
+static inline __attribute__((always_inline)) int htx_hdrs_too_big(const struct htx *htx, int32_t len)
+{
+       return (sizeof(struct htx) + htx->hdrs_data + len > global.tune.bufsize);
+}
+
 /* Defragments an HTX message. It removes unused blocks and unwraps the payloads
  * part. A temporary buffer is used to do so. This function never fails. Most of
  * time, we need keep a ref on a specific HTX block. Thus is <blk> is set, the
@@ -341,6 +349,8 @@ struct htx_blk *htx_add_blk(struct htx *htx, enum htx_blk_type type, uint32_t bl
        struct htx_blk *blk;
 
        BUG_ON(blksz >= 256 << 20);
+       if (unlikely(type < HTX_BLK_EOH && htx_hdrs_too_big(htx, blksz)))
+               return NULL;
        blk = htx_reserve_nxblk(htx, blksz);
        if (!blk)
                return NULL;
@@ -638,6 +648,10 @@ struct htx_blk *htx_replace_blk_value(struct htx *htx, struct htx_blk *blk,
        n  = htx_get_blk_name(htx, blk);
        v  = htx_get_blk_value(htx, blk);
        delta = new.len - old.len;
+
+       if (unlikely(htx_get_blk_type(blk) < HTX_BLK_EOH && htx_hdrs_too_big(htx, delta)))
+               return NULL;
+
        ret = htx_prepare_blk_expansion(htx, blk, delta);
        if (!ret)
                return NULL; /* not enough space */
@@ -1020,6 +1034,9 @@ struct htx_blk *htx_replace_header(struct htx *htx, struct htx_blk *blk,
                return NULL;
 
        delta = name.len + value.len - htx_get_blksz(blk);
+       if (unlikely(htx_hdrs_too_big(htx, delta)))
+               return NULL;
+
        ret = htx_prepare_blk_expansion(htx, blk, delta);
        if (!ret)
                return NULL; /* not enough space */
@@ -1072,6 +1089,10 @@ struct htx_sl *htx_replace_stline(struct htx *htx, struct htx_blk *blk, const st
 
        sz = htx_get_blksz(blk);
        delta = sizeof(*sl) + p1.len + p2.len + p3.len - sz;
+
+       if (unlikely(htx_hdrs_too_big(htx, delta)))
+               return NULL;
+
        ret = htx_prepare_blk_expansion(htx, blk, delta);
        if (!ret)
                return NULL; /* not enough space */