diff --git a/src/transport_layer/node_conn_direct.c b/src/transport_layer/node_conn_direct.c index 85f244ce..0713d88d 100644 --- a/src/transport_layer/node_conn_direct.c +++ b/src/transport_layer/node_conn_direct.c @@ -54,6 +54,7 @@ struct NODE_CONN_DIRECT { ncd_callback cb; void* cb_arg; struct NODE_CONN_DIRECT* next; + void* deliver_up_token; /* handle uasync_call_soon отложенной доставки UP (для отмены при close) */ }; /* ─── forward declarations ─── */ @@ -379,9 +380,21 @@ static void ncd_connect_timeout_cb(void* arg) { static void ncd_deliver_up_cb(void* arg) { struct NODE_CONN_DIRECT* h = (struct NODE_CONN_DIRECT*)arg; + h->deliver_up_token = NULL; /* токен consumed — close больше не отменит освобождённый узел */ if (h->cb) h->cb(h, NCD_EVENT_UP, h->cb_arg); } +/* Планирует отложенную доставку UP и сохраняет токен для возможной отмены при close. */ +static void ncd_schedule_deliver_up(struct UASYNC* ua, struct NODE_CONN_DIRECT* h) { + h->deliver_up_token = uasync_call_soon(ua, h, ncd_deliver_up_cb); +} + +/* Отменяет pending-доставку UP (если ещё не сработала). Без этого h освобождается, + * а отложенный ncd_deliver_up_cb читает freed-память — UAF. */ +static void ncd_cancel_deliver_up(struct NODE_CONN_DIRECT* h, struct UASYNC* ua) { + if (h->deliver_up_token) { uasync_call_soon_cancel(ua, h->deliver_up_token); h->deliver_up_token = NULL; } +} + /* ═══════════ FIN_WAIT ═══════════ */ /* * fin_wait — состояние ожидания подтверждения закрытия от пира. @@ -573,7 +586,7 @@ int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id, entry->handle_count++; *out_handle = h; if (entry->conn && entry->conn->state == 1 && entry->up) { - uasync_call_soon(inst->ua, h, ncd_deliver_up_cb); + ncd_schedule_deliver_up(inst->ua, h); DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open REUSED (ready) node=0x%016llx handles=%d", (unsigned long long)node_id, entry->handle_count); } else if (entry->timed_out) { struct TOPO_NODE* ni = ncd_lookup_node(inst, node_id); @@ -613,7 +626,7 @@ int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id, etcp_conn_add_cbk(conn, ncd_down_cb, entry, ETCP_CBK_EVENT_DOWN); if (conn->state == 1 && entry->up) { - uasync_call_soon(inst->ua, h, ncd_deliver_up_cb); + ncd_schedule_deliver_up(inst->ua, h); DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open REUSED new-entry (ready) node=0x%016llx conn=%p", (unsigned long long)node_id, (void*)conn); } else { { struct TOPO_NODE* ni = ncd_lookup_node(inst, node_id); @@ -732,7 +745,7 @@ int node_conn_direct_open_node(struct UTUN_INSTANCE* inst, uint64_t node_id, entry->handle_count++; *out_handle = h; if (entry->conn && entry->conn->state == 1 && entry->up) { - uasync_call_soon(inst->ua, h, ncd_deliver_up_cb); + ncd_schedule_deliver_up(inst->ua, h); DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node REUSED (ready) node=0x%016llx handles=%d", (unsigned long long)node_id, entry->handle_count); } else if (entry->timed_out) { ncd_revive_entry(entry, inst, ni, specific_sock); @@ -769,7 +782,7 @@ int node_conn_direct_open_node(struct UTUN_INSTANCE* inst, uint64_t node_id, etcp_conn_add_cbk(conn, ncd_down_cb, entry, ETCP_CBK_EVENT_DOWN); if (conn->state == 1 && entry->up) { - uasync_call_soon(inst->ua, h, ncd_deliver_up_cb); + ncd_schedule_deliver_up(inst->ua, h); DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] open_node REUSED new-entry (ready) node=0x%016llx conn=%p", (unsigned long long)node_id, (void*)conn); } else { ncd_create_links(entry, ni, specific_sock); @@ -863,6 +876,7 @@ void node_conn_direct_close(struct NODE_CONN_DIRECT* h) { if (!h) return; struct ncd_entry* entry = h->entry; if (!entry) { u_free(h); return; } + ncd_cancel_deliver_up(h, entry->ua); uint64_t node_id = entry->node_id; struct ETCP_CONN* conn = entry->conn; @@ -953,6 +967,7 @@ void node_conn_direct_force_close(struct NODE_CONN_DIRECT* h) { if (!h) return; if (!h->entry) { DEBUG_ERROR(DEBUG_CATEGORY_NCD, "[ncd] force_close: h=%p h->entry=NULL", h); u_free(h); return; } struct ncd_entry* entry = h->entry; + ncd_cancel_deliver_up(h, entry->ua); DEBUG_INFO(DEBUG_CATEGORY_NCD, "[ncd] force_close h=%p entry=%p node=0x%016llx handles=%d", h, entry, (unsigned long long)entry->node_id, entry->handle_count);