]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: quic: Avoid some crashes upon TX packet allocation failures
authorFrédéric Lécaille <flecaille@haproxy.com>
Wed, 8 Nov 2023 10:31:21 +0000 (11:31 +0100)
committerFrédéric Lécaille <flecaille@haproxy.com>
Thu, 9 Nov 2023 09:32:31 +0000 (10:32 +0100)
If a TX packet cannot be allocated (by qc_build_pkt()), as it can be coalesced
to another one, this leads the TX buffer to have remaining not sent prepared data.
Then haproxy crashes upon a BUG_ON() triggered by the next call to qc_txb_release().
This may happen only during handshakes.

To fix this, qc_build_pkt() returns a new -3 error to dected such allocation
failures followed which is for now on followed by a call to qc_purge_txbuf() to
send the TX prepared data and purge the TX buffer.

Must be backported as far as 2.6.

src/quic_tx.c

index 0a0e4bc79922b442966af8f052337fdba8a4235e..f6976bc0e3cb55202c10655a2c94d2b8fcef393d 100644 (file)
@@ -495,6 +495,9 @@ static int qc_prep_app_pkts(struct quic_conn *qc, struct buffer *buf,
                pkt = qc_build_pkt(&pos, end, qel, &qel->tls_ctx, frms, qc, NULL, 0,
                                   QUIC_PACKET_TYPE_SHORT, must_ack, 0, probe, cc, &err);
                switch (err) {
+               case -3:
+                       qc_purge_txbuf(qc, buf);
+                       goto leave;
                case -2:
                        // trace already emitted by function above
                        goto leave;
@@ -1127,6 +1130,9 @@ int qc_prep_hpkts(struct quic_conn *qc, struct buffer *buf, struct list *qels)
                                               qc, ver, dglen, pkt_type,
                                               must_ack, padding, probe, cc, &err);
                        switch (err) {
+                               case -3:
+                                       qc_purge_tx_buf(qc, buf);
+                                       goto leave;
                                case -2:
                                        // trace already emitted by function above
                                        goto leave;
@@ -2472,8 +2478,8 @@ static inline void quic_tx_packet_init(struct quic_tx_packet *pkt, int type)
  * the end of this buffer, with <pkt_type> as packet type for <qc> QUIC connection
  * at <qel> encryption level with <frms> list of prebuilt frames.
  *
- * Return -2 if the packet could not be allocated or encrypted for any reason,
- * -1 if there was not enough room to build a packet.
+ * Return -3 if the packet could not be allocated, -2 if could not be encrypted for
+ * any reason, -1 if there was not enough room to build a packet.
  * XXX NOTE XXX
  * If you provide provide qc_build_pkt() with a big enough buffer to build a packet as big as
  * possible (to fill an MTU), the unique reason why this function may fail is the congestion
@@ -2502,7 +2508,7 @@ static struct quic_tx_packet *qc_build_pkt(unsigned char **pos,
        pkt = pool_alloc(pool_head_quic_tx_packet);
        if (!pkt) {
                TRACE_DEVEL("Not enough memory for a new packet", QUIC_EV_CONN_TXPKT, qc);
-               *err = -2;
+               *err = -3;
                goto err;
        }