From: Frédéric Lécaille Date: Thu, 1 Sep 2022 08:51:19 +0000 (+0200) Subject: BUG/MINOR: quic: Frames leak during retransmissions X-Git-Tag: v2.7-dev5~20 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a1075209c7a9544bb3f0afa30ac4506c2879fb76;p=thirdparty%2Fhaproxy.git BUG/MINOR: quic: Frames leak during retransmissions The frame which are retransmitted by qc_dgrams_retransmit() are duplicated from sent but not acknowledged packets and added to local frames lists. Some may not have been sent. If not replaced somewhere (linked to the connection) they are lost for ever (leak). We splice the list remaining contents to the packets number space frame list to avoid such a situation. Must be backported to 2.6. --- diff --git a/src/xprt_quic.c b/src/xprt_quic.c index edfda2ee23..3495d4d8b0 100644 --- a/src/xprt_quic.c +++ b/src/xprt_quic.c @@ -4084,15 +4084,24 @@ static void qc_dgrams_retransmit(struct quic_conn *qc) hqel->pktns->tx.pto_probe = 1; qc_send_hdshk_pkts(qc, 1, QUIC_TLS_ENC_LEVEL_INITIAL, &ifrms, QUIC_TLS_ENC_LEVEL_HANDSHAKE, &hfrms); + /* Put back unsent frames in their packet number spaces */ + LIST_SPLICE(&iqel->pktns->tx.frms, &ifrms); + LIST_SPLICE(&hqel->pktns->tx.frms, &hfrms); } } if (hqel->pktns->flags & QUIC_FL_PKTNS_PROBE_NEEDED) { + /* This list has potentially been already used and spliced + * to another one attached to the connection. We must reinitialize it. + */ + LIST_INIT(&hfrms); qc_prep_fast_retrans(qc, hqel, &hfrms, NULL); TRACE_DEVEL("Avail. ack eliciting frames", QUIC_EV_CONN_FRMLIST, qc, &hfrms); if (!LIST_ISEMPTY(&hfrms)) { hqel->pktns->tx.pto_probe = 1; qc_send_hdshk_pkts(qc, 1, QUIC_TLS_ENC_LEVEL_HANDSHAKE, &hfrms, QUIC_TLS_ENC_LEVEL_NONE, NULL); + /* Put back unsent frames into their packet number spaces */ + LIST_SPLICE(&hqel->pktns->tx.frms, &hfrms); } TRACE_STATE("no more need to probe Handshake packet number space", QUIC_EV_CONN_TXPKT, qc); @@ -4104,10 +4113,10 @@ static void qc_dgrams_retransmit(struct quic_conn *qc) } else { int i; - struct list frms1 = LIST_HEAD_INIT(frms1); - struct list frms2 = LIST_HEAD_INIT(frms2); if (hqel->pktns->flags & QUIC_FL_PKTNS_PROBE_NEEDED) { + struct list frms1 = LIST_HEAD_INIT(frms1); + hqel->pktns->tx.pto_probe = 0; for (i = 0; i < QUIC_MAX_NB_PTO_DGRAMS; i++) { qc_prep_fast_retrans(qc, hqel, &frms1, NULL); @@ -4116,6 +4125,8 @@ static void qc_dgrams_retransmit(struct quic_conn *qc) hqel->pktns->tx.pto_probe = 1; qc_send_hdshk_pkts(qc, 1, QUIC_TLS_ENC_LEVEL_HANDSHAKE, &frms1, QUIC_TLS_ENC_LEVEL_NONE, NULL); + /* Put back unsent frames into their packet number spaces */ + LIST_SPLICE(&hqel->pktns->tx.frms, &frms1); } } TRACE_STATE("no more need to probe Handshake packet number space", @@ -4123,6 +4134,9 @@ static void qc_dgrams_retransmit(struct quic_conn *qc) hqel->pktns->flags &= ~QUIC_FL_PKTNS_PROBE_NEEDED; } else if (aqel->pktns->flags & QUIC_FL_PKTNS_PROBE_NEEDED) { + struct list frms2 = LIST_HEAD_INIT(frms2); + struct list frms1 = LIST_HEAD_INIT(frms1); + aqel->pktns->tx.pto_probe = 0; qc_prep_fast_retrans(qc, aqel, &frms1, &frms2); TRACE_PROTO("Avail. ack eliciting frames", QUIC_EV_CONN_FRMLIST, qc, &frms1); @@ -4130,10 +4144,14 @@ static void qc_dgrams_retransmit(struct quic_conn *qc) if (!LIST_ISEMPTY(&frms1)) { aqel->pktns->tx.pto_probe = 1; qc_send_app_probing(qc, &frms1); + /* Put back unsent frames into their packet number spaces */ + LIST_SPLICE(&aqel->pktns->tx.frms, &frms1); } if (!LIST_ISEMPTY(&frms2)) { aqel->pktns->tx.pto_probe = 1; qc_send_app_probing(qc, &frms2); + /* Put back unsent frames into their packet number spaces */ + LIST_SPLICE(&aqel->pktns->tx.frms, &frms2); } TRACE_STATE("no more need to probe 01RTT packet number space", QUIC_EV_CONN_TXPKT, qc);