From: Frantisek Tobias Date: Tue, 6 Jan 2026 13:22:49 +0000 (+0100) Subject: daemon/quic: Avoid invalid element access in the connection expiry heap and only... X-Git-Tag: v6.2.0~2^2~13 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=92167ef8cf298aa3c5fb52a013ea2acc5a1b7a2d;p=thirdparty%2Fknot-resolver.git daemon/quic: Avoid invalid element access in the connection expiry heap and only decrease session ref_count once --- diff --git a/daemon/quic_conn.c b/daemon/quic_conn.c index 9f0fab2f5..46165fc1a 100644 --- a/daemon/quic_conn.c +++ b/daemon/quic_conn.c @@ -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; } diff --git a/daemon/quic_conn.h b/daemon/quic_conn.h index 1fd3873ea..7b407fd3b 100644 --- a/daemon/quic_conn.h +++ b/daemon/quic_conn.h @@ -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; diff --git a/daemon/quic_demux.c b/daemon/quic_demux.c index e5b8348fb..8e1f80509 100644 --- a/daemon/quic_demux.c +++ b/daemon/quic_demux.c @@ -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) diff --git a/daemon/quic_demux.h b/daemon/quic_demux.h index 7baf10e77..fce7a5376 100644 --- a/daemon/quic_demux.h +++ b/daemon/quic_demux.h @@ -5,6 +5,7 @@ #pragma once #include +#include "quic_common.h" #include "session2.h" typedef struct pl_quic_demux_sess_data {