From: Amaury Denoyelle Date: Tue, 24 May 2022 13:24:32 +0000 (+0200) Subject: MINOR: h3: check if frame is valid for stream type X-Git-Tag: v2.6-dev12~119 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=302ecd490bcd8039ba6051d9ef421314e0f5ceee;p=thirdparty%2Fhaproxy.git MINOR: h3: check if frame is valid for stream type Define a new function h3_is_frame_valid(). It returns if a frame is valid or not depending on the stream which received it. For the moment, it is used in h3_decode_qcs() which only deals with bidirectional streams. Soon, uni streams will use the same function, rendering the frame type check useful. --- diff --git a/src/h3.c b/src/h3.c index 3510e64401..11440e726b 100644 --- a/src/h3.c +++ b/src/h3.c @@ -41,10 +41,11 @@ #define h3_debug_hexdump(...) do { } while (0) #endif -#define H3_CF_SETTINGS_SENT 0x00000001 -#define H3_CF_UNI_CTRL_SET 0x00000002 /* Remote H3 Control stream opened */ -#define H3_CF_UNI_QPACK_DEC_SET 0x00000004 /* Remote QPACK decoder stream opened */ -#define H3_CF_UNI_QPACK_ENC_SET 0x00000008 /* Remote QPACK encoder stream opened */ +#define H3_CF_SETTINGS_SENT 0x00000001 /* SETTINGS frame already sent on local control stream */ +#define H3_CF_SETTINGS_RECV 0x00000002 /* SETTINGS frame already received on remote control stream */ +#define H3_CF_UNI_CTRL_SET 0x00000004 /* Remote H3 Control stream opened */ +#define H3_CF_UNI_QPACK_DEC_SET 0x00000008 /* Remote QPACK decoder stream opened */ +#define H3_CF_UNI_QPACK_ENC_SET 0x00000010 /* Remote QPACK encoder stream opened */ /* Default settings */ static uint64_t h3_settings_qpack_max_table_capacity = 0; @@ -172,6 +173,56 @@ static inline size_t h3_decode_frm_header(uint64_t *ftype, uint64_t *flen, return hlen; } +/* Check if H3 frame of type is valid when received on stream . + * + * Returns a boolean. If false, a connection error H3_FRAME_UNEXPECTED should + * be reported. + */ +static int h3_is_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype) +{ + struct h3s *h3s = qcs->ctx; + const uint64_t id = qcs->id; + + BUG_ON_HOT(h3s->type == H3S_T_UNKNOWN); + + switch (ftype) { + case H3_FT_DATA: + case H3_FT_HEADERS: + return h3s->type != H3S_T_CTRL; + + case H3_FT_CANCEL_PUSH: + case H3_FT_GOAWAY: + case H3_FT_MAX_PUSH_ID: + /* Only allowed for control stream. First frame of control + * stream MUST be SETTINGS. + */ + return h3s->type == H3S_T_CTRL && + (h3c->flags & H3_CF_SETTINGS_RECV); + + case H3_FT_SETTINGS: + /* draft-ietf-quic-http34 7.2.4. SETTINGS + * + * If an endpoint receives a second SETTINGS frame on the control + * stream, the endpoint MUST respond with a connection error of type + * H3_FRAME_UNEXPECTED. + */ + return h3s->type == H3S_T_CTRL && + !(h3c->flags & H3_CF_SETTINGS_RECV); + + case H3_FT_PUSH_PROMISE: + return h3s->type != H3S_T_CTRL && + (id & QCS_ID_SRV_INTIATOR_BIT); + + default: + /* draft-ietf-quic-http34 9. Extensions to HTTP/3 + * + * Implementations MUST discard frames [...] that have unknown + * or unsupported types. + */ + return h3s->type != H3S_T_CTRL || (h3c->flags & H3_CF_SETTINGS_RECV); + } +} + /* Parse from buffer a H3 HEADERS frame of length . Data are copied * in a local HTX buffer and transfer to the conn-stream layer. must be * set if this is the last data to transfer from this stream. @@ -340,6 +391,7 @@ static int h3_data_to_htx(struct qcs *qcs, struct ncbuf *buf, uint64_t len, static int h3_decode_qcs(struct qcs *qcs, int fin, void *ctx) { struct ncbuf *rxbuf = &qcs->rx.ncbuf; + struct h3c *h3c = ctx; struct h3s *h3s = qcs->ctx; ssize_t ret; @@ -370,6 +422,11 @@ static int h3_decode_qcs(struct qcs *qcs, int fin, void *ctx) flen = h3s->demux_frame_len; ftype = h3s->demux_frame_type; + if (!h3_is_frame_valid(h3c, qcs, ftype)) { + qcc_emit_cc_app(qcs->qcc, H3_FRAME_UNEXPECTED); + return 1; + } + /* Do not demux incomplete frames except H3 DATA which can be * fragmented in multiple HTX blocks. */ @@ -406,7 +463,9 @@ static int h3_decode_qcs(struct qcs *qcs, int fin, void *ctx) break; default: /* draft-ietf-quic-http34 9. Extensions to HTTP/3 - * unknown frame types MUST be ignored + * + * Implementations MUST discard frames [...] that have unknown + * or unsupported types. */ h3_debug_printf(stderr, "ignore unknown frame type 0x%lx\n", ftype); ret = flen;