BUG/MINOR: quic: fix Initial length value in sent packets
Some checks failed
FreeBSD / clang (push) Waiting to run
Contrib / admin/halog/ (push) Has been cancelled
Contrib / dev/flags/ (push) Has been cancelled
Contrib / dev/haring/ (push) Has been cancelled
Contrib / dev/hpack/ (push) Has been cancelled
Contrib / dev/poll/ (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled

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.
This commit is contained in:
Amaury Denoyelle 2026-06-09 15:15:47 +02:00
parent 9bc37232f4
commit fb38e40ad5

View file

@ -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;