BUG/MINOR: h3: reject server MAX_PUSH_ID frame

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.
This commit is contained in:
Amaury Denoyelle 2026-05-26 10:36:06 +02:00
parent 4a8bb2fe5f
commit e4a5a64198

View file

@ -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