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))