]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: quic: ensure quic-conn survives to the MUX
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 6 Apr 2022 15:22:12 +0000 (17:22 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 7 Apr 2022 08:10:22 +0000 (10:10 +0200)
Rationalize the lifetime of the quic-conn regarding with the MUX. The
quic-conn must not be freed if the MUX is still allocated.

This simplify the MUX code when accessing the quic-conn and removed
possible segfaults.

To implement this, if the quic-conn timer expired, the quic-conn is
released only if the MUX is not allocated. Else, the quic-conn is
flagged with QUIC_FL_CONN_EXP_TIMER. The MUX is then responsible
to call quic_close() which will free the flagged quic-conn.

include/haproxy/xprt_quic-t.h
src/xprt_quic.c

index fad3722c86cc148c2193eb0434ab94c1902d7deb..fbe2ff7735bf3c1535d9bf278907aedeeeb4fb4a 100644 (file)
@@ -664,6 +664,7 @@ enum qc_mux_state {
 #define QUIC_FL_CONN_LISTENER                    (1U << 3)
 #define QUIC_FL_CONN_ACCEPT_REGISTERED           (1U << 4)
 #define QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ (1U << 6)
+#define QUIC_FL_CONN_EXP_TIMER                   (1U << 28) /* timer has expired, quic-conn can be freed */
 #define QUIC_FL_CONN_CLOSING                     (1U << 29)
 #define QUIC_FL_CONN_DRAINING                    (1U << 30)
 #define QUIC_FL_CONN_IMMEDIATE_CLOSE             (1U << 31)
index 6d4262c16bb2e79762dcfd27571610c320bbdcea..a86e7f7546120464a77e5e133a1324a020ab8f4f 100644 (file)
@@ -3802,6 +3802,9 @@ static void quic_conn_release(struct quic_conn *qc)
        struct eb64_node *node;
        struct quic_tls_ctx *app_tls_ctx;
 
+       /* We must not free the quic-conn if the MUX is still allocated. */
+       BUG_ON(qc->mux_state == QC_MUX_READY);
+
        /* free remaining stream descriptors */
        node = eb64_first(&qc->streams_by_id);
        while (node) {
@@ -3866,6 +3869,13 @@ void quic_close(struct connection *conn, void *xprt_ctx)
        /* Next application data can be dropped. */
        qc->mux_state = QC_MUX_RELEASED;
 
+       /* If the quic-conn timer has already expired free the quic-conn. */
+       if (qc->flags & QUIC_FL_CONN_EXP_TIMER) {
+               quic_conn_release(qc);
+               TRACE_LEAVE(QUIC_EV_CONN_CLOSE);
+               return;
+       }
+
        TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc);
 }
 
@@ -4107,7 +4117,16 @@ static struct task *qc_idle_timer_task(struct task *t, void *ctx, unsigned int s
 {
        struct quic_conn *qc = ctx;
 
-       quic_conn_release(qc);
+       /* If the MUX is still alive, keep the quic-conn. The MUX is
+        * responsible to call quic_close to release it.
+        */
+       qc->flags |= QUIC_FL_CONN_EXP_TIMER;
+       if (qc->mux_state != QC_MUX_READY)
+               quic_conn_release(qc);
+
+       /* TODO if the quic-conn cannot be freed because of the MUX, we may at
+        * least clean some parts of it such as the tasklet.
+        */
 
        return NULL;
 }