From: Amaury Denoyelle Date: Thu, 12 Nov 2026 14:40:59 +0000 (+0100) Subject: BUG/MEDIUM: h3: reject standalone FIN on invalid request/response X-Git-Tag: v3.5-dev12~25 X-Git-Url: https://git.kaiwu.me/%7B@url%7D?a=commitdiff_plain;h=026b8cdcd8d59c3d3b1d180e588dd648ec26041f;p=haproxy.git BUG/MEDIUM: h3: reject standalone FIN on invalid request/response HTTP/3 parser has a special code path to handle a standalone FIN. However for a request stream there was no check to ensure that a valid request/response was received before reporting the closure. This would result in an empty HTX buffer with EOM set. On the MUX level, QCS instance would remain accounted in QCC counter, which could result in unnecessary memory consumption. Fix this rejecting a request stream closed with a standalone FIN without a valid request or response received. The stream read is aborted and write is reset using error code H3_REQUEST_INCOMPLETE or H3_MESSAGE_ERROR depending on the proxy side. This allows to quickly release the QCS instance. This must be backported up to 2.6. --- diff --git a/src/h3.c b/src/h3.c index f93ceb433..071d56295 100644 --- a/src/h3.c +++ b/src/h3.c @@ -2019,11 +2019,23 @@ static ssize_t h3_rcv_buf(struct qcs *qcs, struct buffer *b, int fin) goto done; } - if (quic_stream_is_bidi(qcs->id) && qcs_http_handle_standalone_fin(qcs, h3s->st_req == H3S_ST_REQ_TRAILERS)) { - TRACE_ERROR("cannot set EOM", H3_EV_RX_FRAME, qcs->qcc->conn, qcs); - qcc_set_error(qcs->qcc, H3_ERR_INTERNAL_ERROR, 1, - muxc_tevt_type_internal_err); - goto err; + if (quic_stream_is_bidi(qcs->id)) { + /* No header seen, HTTP message is malformed. */ + if (h3s->st_req == H3S_ST_REQ_BEFORE) { + const int code = !conn_is_back(qcs->qcc->conn) ? H3_ERR_REQUEST_INCOMPLETE : H3_ERR_MESSAGE_ERROR; + TRACE_ERROR("incomplete request/response closed with standalone FIN", H3_EV_RX_FRAME, qcs->qcc->conn, qcs); + qcc_abort_stream_read(qcs, code); + qcc_reset_stream(qcs, code, se_tevt_type_proto_err); + qcc_report_glitch(qcs->qcc, 1); + goto done; + } + + if (qcs_http_handle_standalone_fin(qcs, h3s->st_req == H3S_ST_REQ_TRAILERS)) { + TRACE_ERROR("cannot set EOM", H3_EV_RX_FRAME, qcs->qcc->conn, qcs); + qcc_set_error(qcs->qcc, H3_ERR_INTERNAL_ERROR, 1, + muxc_tevt_type_internal_err); + goto err; + } } goto done;