]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: h3: fix MAX_PUSH_ID handling
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 1 Jun 2026 07:47:45 +0000 (09:47 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 1 Jun 2026 07:55:14 +0000 (09:55 +0200)
MAX_PUSH_ID frames are emitted by the client only on the control stream.
These conditions are checked via h3_check_frame_valid() since the
following patch.

  e4a5a64198bb084eaef2e71bfde65704a5db3931
  BUG/MINOR: h3: reject server MAX_PUSH_ID frame

However control stream test was inverted by mistake. This patch fixes
it.

Due to this bug, H3 connections were improperly closed on error by
haproxy for clients which send MAX_PUSH_ID frames. This has been
detected on the QUIC interop with aioquic and neqo clients.

This must be backported up to 3.3.

src/h3.c

index 5a792c02bda756b0a9c57521105191503cfa2925..9d1df37d0c19ce6829bdfbfefa208c09890ca0b2 100644 (file)
--- a/src/h3.c
+++ b/src/h3.c
@@ -403,13 +403,6 @@ static int h3_check_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype
                 * control stream as a connection error of type H3_FRAME_UNEXPECTED.
                 */
 
-               /* RFC 9114 7.2.7. MAX_PUSH_ID
-                *
-                * The MAX_PUSH_ID frame is always sent on the control stream. Receipt
-                * of a MAX_PUSH_ID frame on any other stream MUST be treated as a
-                * connection error of type H3_FRAME_UNEXPECTED.
-                */
-
                if (h3s->type != H3S_T_CTRL)
                        ret = H3_ERR_FRAME_UNEXPECTED;
                else if (!(h3c->flags & H3_CF_SETTINGS_RECV))
@@ -459,7 +452,7 @@ static int h3_check_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype
                 * receipt of a MAX_PUSH_ID frame as a connection error of type
                 * H3_FRAME_UNEXPECTED.
                 */
-               if (h3s->type == H3S_T_CTRL || conn_is_back(qcs->qcc->conn))
+               if (h3s->type != H3S_T_CTRL || conn_is_back(qcs->qcc->conn))
                        ret = H3_ERR_FRAME_UNEXPECTED;
                else if (!(h3c->flags & H3_CF_SETTINGS_RECV))
                        ret = H3_ERR_MISSING_SETTINGS;