]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: quic: strengthen BUG_ON() for unpad Initial packet on client
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 2 Sep 2025 07:22:24 +0000 (09:22 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 2 Sep 2025 08:41:49 +0000 (10:41 +0200)
To avoid anti-amplification limit, it is required that Initial packet
are padded to be at least 1.200 bytes long. On server side, this only
applies to ack-eliciting packets. However, for client side, this is
mandatory for every packets.

This patch adjusts qc_txb_store() BUG_ON statement used to catch too
small Initial packets. On QUIC client side, ack-eliciting flag is now
ignored, thus every packets are checked.

This is labelled as MEDIUM as this BUG_ON() is known to be easily
triggered, as QUIC datagrams encoding function are complex. However,
it's important that a QUIC endpoint respects it, else the peer will drop
the invalid packet and could immediately close the connection.

src/quic_tx.c

index ee354470d533bfcbae8f3f35509433994e7b0b31..4f003240fba99da8e2c335d2d1fd24dd71221bfa 100644 (file)
@@ -159,13 +159,14 @@ struct buffer *qc_get_txb(struct quic_conn *qc)
  * Caller is responsible that there is enough space in the buffer.
  */
 static void qc_txb_store(struct buffer *buf, uint16_t length,
-                         struct quic_tx_packet *first_pkt)
+                         struct quic_tx_packet *first_pkt,
+                         const struct quic_conn *qc)
 {
        BUG_ON_HOT(b_contig_space(buf) < QUIC_DGRAM_HEADLEN); /* this must not happen */
 
        /* If first packet is INITIAL, ensure datagram is sufficiently padded. */
        BUG_ON(first_pkt->type == QUIC_PACKET_TYPE_INITIAL &&
-              (first_pkt->flags & QUIC_FL_TX_PACKET_ACK_ELICITING) &&
+              (qc_is_back(qc) || (first_pkt->flags & QUIC_FL_TX_PACKET_ACK_ELICITING)) &&
               length < QUIC_INITIAL_PACKET_MINLEN);
 
        write_u16(b_tail(buf), length);
@@ -743,7 +744,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
                                         */
                                        if (first_pkt && (first_pkt->type != QUIC_PACKET_TYPE_INITIAL ||
                                                          wrlen >= QUIC_INITIAL_PACKET_MINLEN)) {
-                                               qc_txb_store(buf, wrlen, first_pkt);
+                                               qc_txb_store(buf, wrlen, first_pkt, qc);
                                        }
                                        TRACE_PROTO("could not prepare anymore packet", QUIC_EV_CONN_PHPKTS, qc, qel);
                                        break;
@@ -825,7 +826,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
                        }
                        else {
                                /* Finalize current datagram if not all frames sent. */
-                               qc_txb_store(buf, wrlen, first_pkt);
+                               qc_txb_store(buf, wrlen, first_pkt, qc);
                                first_pkt = NULL;
                                wrlen = dglen = 0;
                                padding = 0;
@@ -844,7 +845,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
 
  out:
        if (first_pkt)
-               qc_txb_store(buf, wrlen, first_pkt);
+               qc_txb_store(buf, wrlen, first_pkt, qc);
 
        if (cc && total) {
                BUG_ON(buf != &qc->tx.cc_buf);