From e0f5afbff8028ed70f45a770b505ea000ceeeccc Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 14 Sep 2026 14:27:38 +0300 Subject: [PATCH] =?UTF-8?q?stcp:=20=D0=B3=D0=B0=D1=81=D0=B8=D1=82=D1=8C=20?= =?UTF-8?q?on=5Fclose=5Fcb/close=5Farg=20=D0=B2=20stcp=5Flink=5Fclose;=20k?= =?UTF-8?q?eepalive:=20=D1=81=D0=BD=D0=B0=D0=BF=D1=88=D0=BE=D1=82+=D1=80?= =?UTF-8?q?=D0=B5=D0=B2=D0=B0=D0=BB=D0=B8=D0=B4=D0=B0=D1=86=D0=B8=D1=8F=20?= =?UTF-8?q?link=20=D0=B4=D0=BE/=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=20=D0=BA?= =?UTF-8?q?=D0=B0=D1=81=D0=BA=D0=B0=D0=B4=D0=B0=20(UAF)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/transport_layer/etcp_keepalive.c | 18 +++++++++++++++--- src/transport_layer/stcp_link.c | 5 +++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/transport_layer/etcp_keepalive.c b/src/transport_layer/etcp_keepalive.c index 55588fdd..a02ba4c0 100644 --- a/src/transport_layer/etcp_keepalive.c +++ b/src/transport_layer/etcp_keepalive.c @@ -129,12 +129,24 @@ static void keepalive_timer_cb(void* arg) { int old_link_status = link->link_status; link->link_status = 0; etcp_fire_link_status_cbk(link, link->link_state, old_link_status); - struct ETCP_CONN *etcp = link->etcp; /* сохранить до каскада: etcp_on_link_down может закрыть conn и освободить link */ + /* Снапшот до каскада: etcp_on_link_down может синхронно закрыть conn/линки + * (topo_recovery → ncd_revive_entry) — link может быть освобождён. */ + struct ETCP_CONN *etcp = link->etcp; + int is_tcp = link->is_tcp; + struct stcp_link *tcp_link = link->tcp_link; + int local_link_id = link->local_link_id; + struct sockaddr_storage raddr = link->remote_addr; + uint8_t remote_ka = link->remote_keepalive; + int link_state = link->link_state, initialized = link->initialized; etcp_on_link_down(etcp, link); if (etcp->state == 2) return; /* conn+link освобождены каскадом, link трогать нельзя */ - if (link->is_tcp && link->tcp_link) { stcp_link_close(link->tcp_link); link->tcp_link = NULL; } + /* каскад мог закрыть линк и без state==2 — проверить, что link ещё в списке */ + int alive = 0; + for (struct ETCP_LINK *x = etcp->links; x; x = x->next) if (x == link) { alive = 1; break; } + if (!alive) return; + if (is_tcp && tcp_link) stcp_link_close(tcp_link); if (old_link_status) { - DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %d down: addr=%s ka=%d remote_ka=%d state=%d init=%d tmo: %llu>%llu els=%llums", link->etcp->log_name, link->local_link_id, sockaddr_storage_to_str(&link->remote_addr).str, link->recv_keepalive, link->remote_keepalive, link->link_state, link->initialized, (unsigned long long)timeout_units, (unsigned long long)elapsed, (unsigned long long)(elapsed/10)); + DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %d down: addr=%s ka=%d remote_ka=%d state=%d init=%d tmo: %llu>%llu els=%llums", etcp->log_name, local_link_id, sockaddr_storage_to_str(&raddr).str, 0, remote_ka, link_state, initialized, (unsigned long long)timeout_units, (unsigned long long)elapsed, (unsigned long long)(elapsed/10)); } } } diff --git a/src/transport_layer/stcp_link.c b/src/transport_layer/stcp_link.c index d7f2ea5f..1ee3de3a 100644 --- a/src/transport_layer/stcp_link.c +++ b/src/transport_layer/stcp_link.c @@ -294,6 +294,11 @@ void stcp_link_close(struct stcp_link *link) { link->closing = 1; link->etcp_conn = NULL; link->etcp_link = NULL; + /* Явный teardown гасит «внезапное» уведомление: отложенный stcp_link_close_impl + * через stcp_conn_do_close → stcp_link_on_stcp_close не должен перевызвать + * on_close_cb с уже освобождённым ETCP_LINK. */ + link->on_close_cb = NULL; + link->close_arg = NULL; if (link->cli) { struct stcp_conn *c = stcp_client_get_conn(link->cli);