]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: h3: reject server MAX_PUSH_ID frame
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 26 May 2026 08:36:06 +0000 (10:36 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 26 May 2026 11:52:04 +0000 (13:52 +0200)
Previously, MAX_PUSH_ID frames were silently ignored both on client and
server sides. However, such frame cannot be emitted by the server.

This patch fixes this by properly issuing connection error
FRAME_UNEXPECTED when receiving a MAX_PUSH_ID frame as a client. This is
implemented by extending h3_check_frame_valid().

This must be backported up to 3.3.

src/h3.c

index 62b69588d327a6a09f29b16c403cbc5e68f0927f..6d58d9f99ee5c21f8b4f6c003cf84b14cd54d4bb 100644 (file)
--- a/src/h3.c
+++ b/src/h3.c
@@ -390,7 +390,6 @@ static int h3_check_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype
 
        case H3_FT_CANCEL_PUSH:
        case H3_FT_GOAWAY:
-       case H3_FT_MAX_PUSH_ID:
                /* RFC 9114 7.2.3. CANCEL_PUSH
                 *
                 * A CANCEL_PUSH frame is sent on the control stream. Receiving a
@@ -449,6 +448,23 @@ static int h3_check_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype
                        ret = H3_ERR_FRAME_UNEXPECTED;
                break;
 
+       case H3_FT_MAX_PUSH_ID:
+               /* 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.
+                *
+                * A server MUST NOT send a MAX_PUSH_ID frame. A client MUST treat the
+                * 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))
+                       ret = H3_ERR_FRAME_UNEXPECTED;
+               else if (!(h3c->flags & H3_CF_SETTINGS_RECV))
+                       ret = H3_ERR_MISSING_SETTINGS;
+               break;
+
        default:
                /* RFC 9114 9. Extensions to HTTP/3
                 *
@@ -1984,10 +2000,6 @@ static ssize_t h3_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
                                goto err;
                        }
                        break;
-               case H3_FT_MAX_PUSH_ID:
-                       /* Not supported */
-                       ret = flen;
-                       break;
                case H3_FT_SETTINGS:
                        ret = h3_parse_settings_frm(qcs->qcc->ctx, b, flen);
                        if (ret < 0) {
@@ -2008,6 +2020,12 @@ static ssize_t h3_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
                         * the client has advertised as a connection error of H3_ID_ERROR.
                         */
                        ret = H3_ERR_ID_ERROR;
+               case H3_FT_MAX_PUSH_ID:
+                       /* h3_check_frame_valid() must reject on client side. */
+                       BUG_ON(conn_is_back(qcs->qcc->conn));
+
+                       /* Not supported. */
+                       ret = flen;
                        break;
                default:
                        /* RFC 9114 Section 9. Extensions to HTTP/3