]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: h3: properly handle incomplete remote uni stream type
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 9 Mar 2023 10:12:32 +0000 (11:12 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 23 Mar 2023 13:38:06 +0000 (14:38 +0100)
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.

src/h3.c

index d52566cb7155335a88d272e20a0dc443e9ecc35b..909942bfd44ff0700456f89122aa16b03ef99522 100644 (file)
--- a/src/h3.c
+++ b/src/h3.c
@@ -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;
        }