Commit 31d61a1ceb for openssl.org
commit 31d61a1ceb1556d729410d4ae59503f49e58cf22
Author: Jakub Zelenka <jakub.zelenka@openssl.foundation>
Date: Thu May 28 12:19:30 2026 +0200
quic: fix handling of the first rxe mfail in qrx_process_pkt
When qrx_ensure_free_rxe() fails at the start of qrx_process_pkt() the
function returned 0 without advancing the PACKET cursor and, for the
first packet in the datagram, without setting first_dcid. The
qrx_process_datagram() loop then re-entered qrx_process_pkt() for the
same bytes with pkt_idx >= 1 and the sentinel first_dcid (id_len = 255),
tripping the assertion in qrx_validate_hdr_early() that asserts
first_dcid->id_len to be lower than QUIC_MAX_CONN_ID_LEN.
The fix goes to malformed label instead. The header has not been decoded
at this point so eop is NULL, which makes the malformed path discard the
rest of the datagram. This is because without an RXE we can process
neither this packet nor any that follow it. This also advances the
cursor and, when the failure is on the first packet, avoids leaving
first_dcid unset for the next iteration. It is consistent with the
other allocation-failure site in the function, which already routes
through malformed.
Reviewed-by: Matt Caswell <matt@openssl.foundation>
Reviewed-by: Saša NedvÄ›dický <sashan@openssl.org>
MergeDate: Fri May 29 14:08:56 2026
(Merged from https://github.com/openssl/openssl/pull/31316)
diff --git a/ssl/quic/quic_record_rx.c b/ssl/quic/quic_record_rx.c
index 0de2d8c9a2..868650a612 100644
--- a/ssl/quic/quic_record_rx.c
+++ b/ssl/quic/quic_record_rx.c
@@ -1031,7 +1031,13 @@ static int qrx_process_pkt(OSSL_QRX *qrx, QUIC_URXE *urxe,
*/
rxe = qrx_ensure_free_rxe(qrx, PACKET_remaining(pkt));
if (rxe == NULL)
- return 0;
+ /*
+ * Allocation failure, treat as malformed as we cannot process this
+ * packet. The header has not been read yet so we do not know the
+ * packet size and cannot skip just this packet, so we drop the rest of
+ * the datagram instead.
+ */
+ goto malformed;
/* Have we already processed this packet? */
if (pkt_is_marked(&urxe->processed, pkt_idx))