BUG/MINOR: h3: properly handle incomplete remote uni stream type

A H3 unidirectional stream is always opened with its stream type first
encoded as a QUIC variable integer. If the STREAM frame contains some
data but not enough to decode this varint, haproxy would crash due to an
ABORT_NOW() statement.

To fix this, ensure we support an incomplete stream type. In this case,
h3_init_uni_stream() returns 0 and the buffer content is not cleared.
Stream decoding will resume when new data are received for this stream
which should be enough to decode the stream type varint.

This bug has never occured on production because standard H3 stream types
are small enough to be encoded on a single byte.

This should be backported up to 2.6.
This commit is contained in:
Amaury Denoyelle 2023-03-09 11:12:32 +01:00
parent 1751db140a
commit 5aa21c1748

View File

@ -181,7 +181,9 @@ static ssize_t h3_init_uni_stream(struct h3c *h3c, struct qcs *qcs,
ret = b_quic_dec_int(&type, b, &len);
if (!ret) {
ABORT_NOW();
/* not enough data to decode uni stream type, retry later */
TRACE_DATA("cannot decode uni stream type due to incomplete data", H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
goto out;
}
switch (type) {
@ -235,6 +237,7 @@ static ssize_t h3_init_uni_stream(struct h3c *h3c, struct qcs *qcs,
h3s->flags |= H3_SF_UNI_INIT;
out:
TRACE_LEAVE(H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
return len;
@ -994,10 +997,15 @@ static ssize_t h3_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
TRACE_ENTER(H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
if (quic_stream_is_uni(qcs->id) && !(h3s->flags & H3_SF_UNI_INIT)) {
if ((ret = h3_init_uni_stream(h3c, qcs, b)) < 0) {
ret = h3_init_uni_stream(h3c, qcs, b);
if (ret < 0) {
TRACE_ERROR("cannot initialize uni stream", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
goto err;
}
else if (!ret) {
/* not enough data to initialize uni stream, retry later */
goto done;
}
total += ret;
}