]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
daemon/quic: Avoid invalid element access in the connection expiry heap and only...
authorFrantisek Tobias <frantisek.tobias@nic.cz>
Tue, 6 Jan 2026 13:22:49 +0000 (14:22 +0100)
committerFrantisek Tobias <frantisek.tobias@nic.cz>
Wed, 7 Jan 2026 13:44:27 +0000 (14:44 +0100)
daemon/quic_conn.c
daemon/quic_conn.h
daemon/quic_demux.c
daemon/quic_demux.h

index 9f0fab2f5940238387a1a858d992db29d36f1415..46165fc1a8b6be9a913bbc26c3054acd35890840 100644 (file)
@@ -795,6 +795,7 @@ static int pl_quic_conn_sess_init(struct session2 *session, void *sess_data, voi
 {
        struct pl_quic_conn_sess_data *conn = sess_data;
        conn->state = 0;
+       conn->disconnected = false;
        conn->path = calloc(1, sizeof(ngtcp2_path));
        if (!conn->path) {
                return kr_error(ENOMEM);
@@ -856,6 +857,7 @@ static int pl_quic_conn_sess_deinit(struct session2 *session, void *sess_data)
        struct pl_quic_conn_sess_data *conn = sess_data;
        while (session2_tasklist_del_first(session, false) != NULL);
 
+       session2_timer_stop(session);
        struct pl_quic_stream_sess_data *s_node;
        WALK_LIST_FIRST(s_node, conn->streams) {
                struct pl_quic_stream_sess_data *s =
@@ -897,7 +899,6 @@ static int pl_quic_conn_sess_deinit(struct session2 *session, void *sess_data)
        ngtcp2_conn_del(conn->conn);
        conn->conn = NULL;
 
-       session2_timer_stop(session);
        return kr_ok();
 }
 
@@ -914,7 +915,10 @@ static enum protolayer_event_cb_result pl_quic_conn_event_unwrap(
        if (event == PROTOLAYER_EVENT_DISCONNECT ||
                        event == PROTOLAYER_EVENT_CLOSE ||
                        event == PROTOLAYER_EVENT_FORCE_CLOSE) {
-               session2_dec_refs(session);
+               if (!conn->disconnected) {
+                       conn->disconnected = true;
+                       session2_dec_refs(session);
+               }
                return PROTOLAYER_EVENT_CONSUME;
        }
 
index 1fd3873ea3bd85179c57c11fc8bb86573c492d83..7b407fd3b6c6b272b53884b183ce5f2ec893fb2a 100644 (file)
@@ -63,6 +63,10 @@ struct pl_quic_conn_sess_data {
        queue_t(struct pl_quic_stream_sess_data *) pending_unwrap;
        bool is_server;
        bool retry_sent;
+       /* defer can keep the session alive even if the connection timed out or
+        * terminated. To avoid decreasing the refcount more than once in
+        * quic_conn:pl_quic_event_unwrap this boolean value is used. */
+       bool disconnected;
        ngtcp2_cid dcid;
        ngtcp2_cid scid;
        ngtcp2_cid odcid;
index e5b8348fb791e9330d3422fe6a0224e9fac82c36..8e1f80509412182ec1beb20aa690a40300dce894 100644 (file)
@@ -119,20 +119,22 @@ void kr_quic_table_rem(struct pl_quic_conn_sess_data *conn,
                                continue;
                        }
                        kr_quic_table_rem2(pcid, table);
+                       conn->cid_pointers--;
                }
 
-               conn->cid_pointers--;
                free(scids);
-       } else {
-               kr_quic_cid_t **pcid = kr_quic_table_lookup2(&conn->dcid, table);
-               if (pcid != NULL) {
-                       kr_quic_table_rem2(pcid, table);
-               }
        }
-
+       
        int pos = heap_find(table->expiry_heap, (heap_val_t *)conn);
-       heap_delete(table->expiry_heap, pos);
-       table->usage--;
+       /* Since deferred iteration context increases the session ref_count
+        * it is possible that the session will exist after being removed
+        * from the expiry heap. In such case no cid is found and the
+        * the heap_find function returns 0, which is not a valid value
+        * because the heap index starts at 1. */
+       if (pos != 0) {
+               heap_delete(table->expiry_heap, pos);
+               table->usage--;
+       }
 }
 
 void kr_quic_table_free(kr_quic_table_t *table)
index 7baf10e77d47907bf0ee50da62f1af6fd898b666..fce7a5376564596711c66cf545359d4ffe86ca31 100644 (file)
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <ngtcp2/ngtcp2.h>
+#include "quic_common.h"
 #include "session2.h"
 
 typedef struct pl_quic_demux_sess_data {