From 42d96f118d097afcacfee7ef73db731c0bbd15d6 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Thu, 2 Jul 2026 17:14:38 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20swap=20queue=5Fentry=5Ffree/queue=5Fdgra?= =?UTF-8?q?m=5Ffree=20order=20in=2027=20places=20=E2=80=94=20prevents=20UA?= =?UTF-8?q?F=20when=20dgram=5Ffree=20accesses=20freed=20entry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uasync: replace raw socket_node* handle with packed index — fixes UAF after socket_array realloc tcp_io: defer u_free in tcp_conn_destroy via uasync_call_soon — prevents callback-chain UAF tcp_io: guard read_cb/write_cb with NULL queue checks after deferred destroy tcp_io: save read_queue to local before queue_data_put + NULL guard after route_connectivity: linked-list probe_ctx — cancel all parallel probes before nq free --- src/etcp_api.c | 6 +++--- src/etcp_router.c | 2 +- src/nat_transport.c | 10 +++++----- src/proxy/icmp_proxy.c | 4 ++-- src/proxy/udp_proxy.c | 4 ++-- tests/test_etcp_router.c | 14 +++++++------- tests/test_etcp_router_unit.c | 2 +- tests/test_icmp_proxy.c | 4 ++-- tests/test_udp_proxy.c | 4 ++-- 9 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/etcp_api.c b/src/etcp_api.c index 2d1ebb71..9dca44a7 100644 --- a/src/etcp_api.c +++ b/src/etcp_api.c @@ -52,14 +52,14 @@ void etcp_int_recv(struct ll_queue* queue, void* arg) { if (!queue || !conn) return; struct ll_entry* e = queue_data_get(queue); if (!e) { queue_resume_callback(queue); return; } - if (!e->dgram || e->len == 0) { queue_entry_free(e); queue_dgram_free(e); queue_resume_callback(queue); return; } + if (!e->dgram || e->len == 0) { queue_dgram_free(e); queue_entry_free(e); queue_resume_callback(queue); return; } uint8_t id = e->dgram[0]; struct UTUN_INSTANCE* inst = conn->instance; - if (!inst) { queue_entry_free(e); queue_dgram_free(e); queue_resume_callback(queue); return; } + if (!inst) { queue_dgram_free(e); queue_entry_free(e); queue_resume_callback(queue); return; } if (inst->api_bindings.callbacks[id]) inst->api_bindings.callbacks[id](conn, e); else if (inst->api_bindings.callbacks[0]) inst->api_bindings.callbacks[0](conn, e); - else { queue_entry_free(e); queue_dgram_free(e); } + else { queue_dgram_free(e); queue_entry_free(e); } queue_resume_callback(queue); } diff --git a/src/etcp_router.c b/src/etcp_router.c index 411a99ce..4c8538fb 100644 --- a/src/etcp_router.c +++ b/src/etcp_router.c @@ -550,7 +550,7 @@ static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) if (!qe) { queue_dgram_free(entry); queue_entry_free(entry); return; } *(uint32_t*)qe->data = seq; qe->dgram = u_malloc(pl_len); - if (!qe->dgram) { queue_entry_free(qe); queue_dgram_free(entry); queue_entry_free(entry); return; } + if (!qe->dgram) { queue_dgram_free(qe); queue_entry_free(qe); queue_dgram_free(entry); queue_entry_free(entry); return; } qe->len = pl_len; memcpy(qe->dgram, pl, pl_len); diff --git a/src/nat_transport.c b/src/nat_transport.c index 22a1613b..76681d44 100644 --- a/src/nat_transport.c +++ b/src/nat_transport.c @@ -51,7 +51,7 @@ static void nat_transport_client_tun_out_cb(struct ll_queue* q, void* arg) { if (ret != 0) { DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT client: etcp_route_send to provider %016llx failed", (unsigned long long)tr->nat_via_node_id); - queue_entry_free(new_entry); queue_dgram_free(new_entry); + queue_dgram_free(new_entry); queue_entry_free(new_entry); } } @@ -94,21 +94,21 @@ static void nat_transport_provider_tun_out_cb(struct ll_queue* q, void* arg) { if (send_ret != 0) { DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT provider: etcp_route_send back to node %016llx failed", (unsigned long long)entry->src_node_id); - queue_entry_free(new_entry); queue_dgram_free(new_entry); + queue_dgram_free(new_entry); queue_entry_free(new_entry); } } // ETCP_ID_NAT receive via etcp_router: CLIENT gets response, PROVIDER gets request static void nat_transport_etcp_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) { if (!conn || !entry || !entry->dgram || entry->len < NAT_SVC_HDR_SIZE) { - if (entry) { queue_entry_free(entry); queue_dgram_free(entry); } + if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return; } struct UTUN_INSTANCE* inst = conn->instance; - if (!inst) { queue_entry_free(entry); queue_dgram_free(entry); return; } + if (!inst) { queue_dgram_free(entry); queue_entry_free(entry); return; } struct nat_transport_ctx* tr = &inst->nat_tr; struct eim_nat_ctx* ctx = &inst->nat; - if (!ctx->initialized) { queue_entry_free(entry); queue_dgram_free(entry); return; } + if (!ctx->initialized) { queue_dgram_free(entry); queue_entry_free(entry); return; } uint64_t src_node_id; memcpy(&src_node_id, entry->dgram + 1, 8); diff --git a/src/proxy/icmp_proxy.c b/src/proxy/icmp_proxy.c index 1551e584..c730d5cb 100644 --- a/src/proxy/icmp_proxy.c +++ b/src/proxy/icmp_proxy.c @@ -173,7 +173,7 @@ drop: // Сторона клиента: принять REPLY, доставить echo ответ в TUN // ==================================================================== static void client_handle_reply(struct ETCP_CONN* conn, struct ll_entry* entry) { - if (entry->len < ICMP_PROXY_HDR_SIZE + 1) { queue_entry_free(entry); queue_dgram_free(entry); return; } + if (entry->len < ICMP_PROXY_HDR_SIZE + 1) { queue_dgram_free(entry); queue_entry_free(entry); return; } uint32_t src_ip; uint32_t orig_src_ip; uint16_t echo_id, echo_seq; @@ -194,7 +194,7 @@ static void client_handle_reply(struct ETCP_CONN* conn, struct ll_entry* entry) // ==================================================================== void icmp_proxy_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) { if (!entry || !entry->dgram || entry->len < 2) { - if (entry) { queue_entry_free(entry); queue_dgram_free(entry); } + if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return; } uint8_t subcmd = entry->dgram[1]; diff --git a/src/proxy/udp_proxy.c b/src/proxy/udp_proxy.c index 35d427ab..bb20dfeb 100644 --- a/src/proxy/udp_proxy.c +++ b/src/proxy/udp_proxy.c @@ -114,7 +114,7 @@ drop: // Сторона клиента: принять REPLY, доставить в TUN // ==================================================================== static void client_handle_reply(struct ETCP_CONN* conn, struct ll_entry* entry) { - if (entry->len < UDP_PROXY_HDR_SIZE + 1) { queue_entry_free(entry); queue_dgram_free(entry); return; } + if (entry->len < UDP_PROXY_HDR_SIZE + 1) { queue_dgram_free(entry); queue_entry_free(entry); return; } // svc_id уже обработан диспетчером etcp_router uint32_t src_ip, dst_ip; uint16_t src_port, dst_port; @@ -136,7 +136,7 @@ static void client_handle_reply(struct ETCP_CONN* conn, struct ll_entry* entry) // ==================================================================== void udp_proxy_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) { if (!entry || !entry->dgram || entry->len < 2) { - if (entry) { queue_entry_free(entry); queue_dgram_free(entry); } + if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return; } uint8_t subcmd = entry->dgram[1]; diff --git a/tests/test_etcp_router.c b/tests/test_etcp_router.c index f7d4a0cc..b3d38e32 100644 --- a/tests/test_etcp_router.c +++ b/tests/test_etcp_router.c @@ -105,7 +105,7 @@ static struct ETCP_CONN* first_conn(struct UTUN_INSTANCE* inst) { static void srv_handler(struct ETCP_CONN* conn, struct ll_entry* entry) { (void)conn; if (!entry || !entry->dgram || entry->len < 10) { // svc_id(1) + subcmd(1) + seq(4) + data_len(4) - if (entry) { queue_entry_free(entry); queue_dgram_free(entry); } + if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return; } uint8_t subcmd = entry->dgram[1]; @@ -123,7 +123,7 @@ static void srv_handler(struct ETCP_CONN* conn, struct ll_entry* entry) { } else { fwd_rcvd++; } - queue_entry_free(entry); queue_dgram_free(entry); + queue_dgram_free(entry); queue_entry_free(entry); // Send reply back if (!g_test_done && reply_sent < TOTAL_PACKETS) { @@ -139,7 +139,7 @@ static void srv_handler(struct ETCP_CONN* conn, struct ll_entry* entry) { etcp_route_send(srv, client_node_id, re, 0); reply_sent++; } } } else { - queue_entry_free(entry); queue_dgram_free(entry); + queue_dgram_free(entry); queue_entry_free(entry); } } @@ -147,7 +147,7 @@ static void srv_handler(struct ETCP_CONN* conn, struct ll_entry* entry) { static void cli_handler(struct ETCP_CONN* conn, struct ll_entry* entry) { (void)conn; if (!entry || !entry->dgram || entry->len < 10) { - if (entry) { queue_entry_free(entry); queue_dgram_free(entry); } + if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return; } uint8_t subcmd = entry->dgram[1]; @@ -166,7 +166,7 @@ static void cli_handler(struct ETCP_CONN* conn, struct ll_entry* entry) { reply_rcvd++; } } - queue_entry_free(entry); queue_dgram_free(entry); + queue_dgram_free(entry); queue_entry_free(entry); } // ======================== Loopback test (no ETCP) ======================== @@ -178,7 +178,7 @@ static void loop_handler(struct ETCP_CONN* conn, struct ll_entry* entry) { loop_rcvd++; if (entry->dgram[1] == 0xAA && entry->dgram[2] == 0xBB && entry->dgram[3] == 0xCC) loop_ok = 1; } - if (entry) { queue_entry_free(entry); queue_dgram_free(entry); } + if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } } static int test_loopback(void) { @@ -250,7 +250,7 @@ static void monitor(void* arg) { struct ll_entry* e = queue_entry_new(0); if (e) { e->dgram = u_malloc(10 + data_len); memcpy(e->dgram, buf, 10 + data_len); e->len = 10 + data_len; if (etcp_route_send(cli, server_node_id, e, 0) == 0) fwd_sent++; - else { queue_entry_free(e); queue_dgram_free(e); } + else { queue_dgram_free(e); queue_entry_free(e); } } } diff --git a/tests/test_etcp_router_unit.c b/tests/test_etcp_router_unit.c index 6811fd06..1fac2c79 100644 --- a/tests/test_etcp_router_unit.c +++ b/tests/test_etcp_router_unit.c @@ -48,7 +48,7 @@ static void test_handler(struct ETCP_CONN* conn, struct ll_entry* entry) { return; } if (entry->dgram[1] != rx.marker) { rx.errors++; } else { rx.delivered++; rx.last_seq = rx.expected_seq; rx.expected_seq++; } - queue_entry_free(entry); queue_dgram_free(entry); + queue_dgram_free(entry); queue_entry_free(entry); } static void rx_reset(uint8_t marker) { diff --git a/tests/test_icmp_proxy.c b/tests/test_icmp_proxy.c index 07875aff..917bc3a8 100644 --- a/tests/test_icmp_proxy.c +++ b/tests/test_icmp_proxy.c @@ -85,7 +85,7 @@ static void* g_to_id = NULL; static void cli_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) { (void)conn; if (!entry || !entry->dgram || entry->len < ICMP_PROXY_HDR_SIZE + 1) { - if (entry) { queue_entry_free(entry); queue_dgram_free(entry); } return; + if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return; } if (entry->dgram[1] == ICMP_PROXY_SUBCMD_REPLY) { uint16_t rid, rseq; @@ -105,7 +105,7 @@ static void cli_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) { g_done = -1; } } - queue_entry_free(entry); queue_dgram_free(entry); + queue_dgram_free(entry); queue_entry_free(entry); } static void monitor(void* arg) { diff --git a/tests/test_udp_proxy.c b/tests/test_udp_proxy.c index 93e62d6b..bc057467 100644 --- a/tests/test_udp_proxy.c +++ b/tests/test_udp_proxy.c @@ -95,7 +95,7 @@ static void udp_echo_cb(socket_t sock, void* arg) { static void cli_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) { (void)conn; if (!entry || !entry->dgram || entry->len < UDP_PROXY_HDR_SIZE + 1) { - if (entry) { queue_entry_free(entry); queue_dgram_free(entry); } return; + if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return; } // svc_id(1) + subcmd(1) + sender_node_id(8) + src_ip(4) + src_port(2) + dst_ip(4) + dst_port(2) + payload size_t payload_len = entry->len - UDP_PROXY_HDR_SIZE; @@ -108,7 +108,7 @@ static void cli_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) { g_done = -1; } } - queue_entry_free(entry); queue_dgram_free(entry); + queue_dgram_free(entry); queue_entry_free(entry); } static void monitor(void* arg) {