]> git.kaiwu.me - haproxy.git/commit
BUG/MAJOR: quic: don't reference a retired CID from a NEW_CONNECTION_ID frame
authorGihyeon Ryu <rlgusryu@gmail.com>
Wed, 11 Nov 2026 10:00:11 +0000 (10:00 +0000)
committerFrederic Lecaille <flecaille@haproxy.com>
Thu, 12 Nov 2026 09:42:55 +0000 (10:42 +0100)
commit827354038df8b6fb4603116ecc85ec2d54478cd5
tree440c18e6edd17f58803c485a3e61fc770c3e3d9c
parentffcecaca0dcf50c19fafa9970d982465b211289a
BUG/MAJOR: quic: don't reference a retired CID from a NEW_CONNECTION_ID frame

A NEW_CONNECTION_ID frame built by HAProxy only stores pointers to the
CID and stateless reset token of its quic_connection_id. When a
RETIRE_CONNECTION_ID frame is received, the CID is freed at once, while
a NEW_CONNECTION_ID frame for it may still be queued, in flight, or be
duplicated later for a retransmission. A client can trigger it by
retiring sequence numbers 1 and 2 in the same packet: the second frame
frees the CID allocated by the first one, whose frame is not sent yet.
The frame is then built from freed memory. In a default build, the pool
cache gives the object back to the next CID of the same connection, so
two frames carry the same CID. Without the pool cache, freed heap memory
is sent to the peer, and ASan reports a heap-use-after-free.

struct qf_new_connection_id now stores the CID and the token instead of
pointers, and quic_connection_id_to_frm_cpy() and the frame duplication
copy them. The parser copies them as well and rejects a CID length above
20 (RFC 9000 section 19.15). quic_frame does not grow, since its union
already holds a larger member.

This should be backported to 2.8 and later.
include/haproxy/quic_cid.h
include/haproxy/quic_frame-t.h
src/quic_frame.c