On backend connections, quic_rx_pkt_parse() accepts long header packets
with an unsupported version and Version Negotiation packets, as these
checks only apply to listeners. Such packets keep the
QUIC_PACKET_TYPE_UNKNOWN type, which maps to no encryption level, and hit
BUG_ON(!qel || !pktns) in qc_enc_level_alloc() from qc_try_rm_hp(), or a
NULL dereference without DEBUG_STRICT.
No malicious peer is required: a server which does not support the
version selected by haproxy responds with a Version Negotiation packet
(RFC 9000 6.1). A malicious server or an on-path attacker may also send a
packet with an unsupported version.
Drop these packets on backend connections, as required by RFC 9000 5.2.1,
since version negotiation is not supported on the backend side. To do
so, export quic_version_VN_reserved and compare the packet version to it
instead of testing a null version number.
This should be backported up to 3.3, where it was introduced by
43d88a44f
("MINOR: quic-be: Datagrams and packet parsing support").
Signed-off-by: William Dauchy <wdauchy@gmail.com>
extern const struct quic_version *quic_version_draft_29;
extern const struct quic_version *quic_version_1;
extern const struct quic_version *quic_version_2;
+extern const struct quic_version quic_version_VN_reserved;
/* unused: 0x01 */
/* Flag the packet number space as requiring an ACK frame to be sent. */
goto drop_silent;
}
+ if (!l && (!pkt->version || pkt->version == &quic_version_VN_reserved)) {
+ TRACE_PROTO("RX unsupported version or VN packet on backend",
+ QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version);
+ goto drop;
+ }
+
if (pkt->type == QUIC_PACKET_TYPE_INITIAL) {
/* For Initial packets, and for servers (QUIC clients connections),
* there is no Initial connection IDs storage.