]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: mux_quic: fix crash on QCS double remote close
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 21 Oct 2026 07:34:57 +0000 (09:34 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 21 Oct 2026 11:49:21 +0000 (13:49 +0200)
A QCS instance must only be closed remotely once. A BUG_ON() enforces
it, so that FIN signalling to the upper layer is correct.

There exists a possible case of a double remote closure after data
transfer between two adjacent buffers on parser blocking. This only
happens if the next buffer is emptied and a standalone FIN is then
received. First qcs_close_remote() will be called during the empty
STREAM FIN reception. This is called again on qcc_decode_qcs() after
consuming data when dealing with the empty remaining buffer.

This patch fixes this by preventing the second call to
qcs_close_remote() in case an empty buffer is detected.

This bug is not easily reproducible as it is highly dependent on the
precise order of these different operations.

This must be backported up to 3.2, as this is the first release which
support multiple QCS Rx buffers.

src/mux_quic.c

index c8c6655e010c88afc2733880a38ad7c287b78568..82fe6c393fee3cc66794368344d558ebaecc01fe 100644 (file)
@@ -1543,7 +1543,12 @@ static int qcc_decode_qcs(struct qcc *qcc, struct qcs *qcs)
                         */
                        if (qcs->flags & QC_SF_SIZE_KNOWN && !eb_is_empty(&qcs->rx.bufs)) {
                                const ncb_sz_t avail = qcs_rx_avail_data(qcs);
-                               if (qcs->rx.offset + avail == qcs->rx.offset_max)
+
+                               /* A remotely closed QCS cannot have a non empty Rx buffer left to parse. */
+                               BUG_ON(avail && qcs_is_close_remote(qcs));
+
+                               /* <avail> null check ensures an empty buffer is ignored. */
+                               if (avail && qcs->rx.offset + avail == qcs->rx.offset_max)
                                        qcs_close_remote(qcs);
                        }
                }