Fix TCP proxy use-after-free during synchronous close

This commit is contained in:
evgeny committed 2026-09-30 10:43:02 +03:00
1 parent 745ec3dbd2
commit 52ffb91101
2 files changed
+23 -2

No files matched your search

+14 -2
View File
@@ -55,6 +55,18 @@ static int send_msg(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t dst,
return proxy_send(inst, dst, ETCP_RT_ID_TCP_PROXY_CLIENT, subcmd, sid, data, len, force);
}
// CLOSE может синхронно освободить rc через on_closed: резервируем состояние до push.
static void server_queue_close(struct tcp_proxy_server_conn* rc) {
if (rc->close_queued) return;
rc->close_queued = 1;
DEBUG_DEBUG(DEBUG_CATEGORY_PROXY, "proxy exit: queue CLOSE peer=%016llx sid=%08x fd=%d",
(unsigned long long)rc->peer_node_id, rc->stream_id, (int)rc->tc->sock);
if (tcp_conn_push_close(rc->tc) == 0) return;
rc->close_queued = 0;
DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "proxy exit: queue CLOSE failed peer=%016llx sid=%08x",
(unsigned long long)rc->peer_node_id, rc->stream_id);
}
// FIN относится только к прочитанному направлению: сначала передаём весь read_queue.
static void server_maybe_finish(struct tcp_proxy_server_conn* rc) {
struct tcp_conn* tc = rc->tc;
@@ -64,7 +76,7 @@ static void server_maybe_finish(struct tcp_proxy_server_conn* rc) {
proxy_flow_flush(&rc->flow);
}
if (rc->flow.fin_sent && rc->flow.fin_received && tc->fin_local) {
if (tcp_conn_push_close(tc) == 0) rc->close_queued = 1;
server_queue_close(rc);
}
}
@@ -377,7 +389,7 @@ void tcp_proxy_server_handle_close(struct UTUN_INSTANCE* inst, uint64_t peer, ui
}
}
if (rc->tc->connected) {
if (!rc->close_queued && tcp_conn_push_close(rc->tc) == 0) rc->close_queued = 1;
server_queue_close(rc);
} else tcp_proxy_server_conn_free(rc);
}