From fb38e40ad5751090992cde15d919866b1e91b8aa Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Tue, 9 Jun 2026 15:15:47 +0200 Subject: [PATCH] BUG/MINOR: quic: fix Initial length value in sent packets QUIC packets using a long header contains a Length field. Its value is the length of the content following it, i.e. the packet number field and the remaining payload (QUIC frames and TLS AEAD tag). Computation to determine the packet length is performed in qc_do_build_pkt(). However this calculation is incorrect when Initial padding is added on a small enough Initial packet. As length field is encoded as a varint, it changes the field size which grow from one to two bytes, reducing in effect the total required padding length from one byte. However, length value is not updated and thus is one byte bigger than the final packet payload with padding. Fix this calculation by reducing the length value after padding size has been adjusted. This bug caused the peer to reject such faulty packets. However, its impact is minor as it only happened only for Initial with small enough payload. Packets used for ClientHello/ServerHello exchanges should be large enough and typically not concerned by this bug, except maybe in case of fragmentation. This bug was detected by testing QUIC backend with a quiche server. The server endpoint reported the faulty packets with the following trace : [2026-06-09T13:42:13.694179158Z ERROR quiche_server] 1b1b961c9c4ae1f470f3687510b120da1f5d5f5a recv failed: InvalidPacket This must be backported up to 3.0. --- src/quic_tx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/quic_tx.c b/src/quic_tx.c index dee267901..da3cd4d44 100644 --- a/src/quic_tx.c +++ b/src/quic_tx.c @@ -2029,8 +2029,8 @@ static int qc_do_build_pkt(unsigned char *pos, const unsigned char *end, /* Handle Initial packet padding if necessary. */ if (padding && dglen < QUIC_INITIAL_PACKET_MINLEN) { padding_len = QUIC_INITIAL_PACKET_MINLEN - dglen; - len += padding_len; + /* Update size of packet length field with new PADDING data. */ if (pkt->type != QUIC_PACKET_TYPE_SHORT) { size_t len_sz_diff = quic_int_getsize(len) - len_sz; @@ -2038,6 +2038,7 @@ static int qc_do_build_pkt(unsigned char *pos, const unsigned char *end, padding_len -= len_sz_diff; len_sz += len_sz_diff; dglen += len_sz_diff; + len -= len_sz_diff; } } } @@ -2074,6 +2075,7 @@ static int qc_do_build_pkt(unsigned char *pos, const unsigned char *end, len += padding_len; } + /* Encode length field : length of PN and payload (frames + TLS AEAD tag). */ if (pkt->type != QUIC_PACKET_TYPE_SHORT && !quic_enc_int(&pos, end, len)) goto no_room;