Browse Source

tcp_io: deferred free in tcp_conn_destroy to prevent UAF in callback chain

chatgui
Evgeny 3 months ago
parent
commit
e66156eb49
  1. 13
      lib/tcp_io.c
  2. 1
      lib/tcp_io.h
  3. 17
      src/route_connectivity.c
  4. 2
      src/route_node.h

13
lib/tcp_io.c

@ -104,8 +104,17 @@ struct tcp_conn* tcp_conn_create(
return tc;
}
static void tcp_conn_deferred_free(void* arg) {
struct tcp_conn* tc = (struct tcp_conn*)arg;
if (tc->entry_pool) memory_pool_destroy(tc->entry_pool);
if (tc->data_pool) memory_pool_destroy(tc->data_pool);
u_free(tc);
}
void tcp_conn_destroy(struct tcp_conn* tc) {
if (!tc) return;
if (tc->destroyed) return;
tc->destroyed = 1;
DEBUG_DEBUG(DEBUG_CATEGORY_SOCKET, "tcp_conn_destroy: fd=%d connected=%d error=%d fin_remote=%d fin_local=%d closed=%d",
(int)tc->sock, tc->connected, tc->error, tc->fin_remote, tc->fin_local, tc->closed);
@ -132,9 +141,7 @@ void tcp_conn_destroy(struct tcp_conn* tc) {
if (tc->write_buf) memory_pool_free(tc->data_pool, tc->write_buf);
if (tc->sock != SOCKET_INVALID) { socket_close_wrapper(tc->sock); tc->sock = SOCKET_INVALID; }
memory_pool_destroy(tc->entry_pool);
memory_pool_destroy(tc->data_pool);
u_free(tc);
uasync_call_soon(tc->ua, tc, tcp_conn_deferred_free);
}
static void tcp_conn_handle_error(struct tcp_conn* tc, int err)

1
lib/tcp_io.h

@ -46,6 +46,7 @@ struct tcp_conn {
uint8_t fin_remote; // FIN получен от удалённой стороны (recv == 0)
uint8_t fin_local; // FIN отправлен удалённой стороне (shutdown SHUT_WR)
uint8_t closed; // сокет полностью закрыт (close)
uint8_t destroyed; // 1 = tcp_conn_destroy вызван, tc ожидает отложенного free
// Частичная отправка (из data_pool, не в очереди — досылается первой)
uint8_t* write_buf;

17
src/route_connectivity.c

@ -20,6 +20,7 @@
#define CONN_MAX_SOCKET_CANDIDATES 8
struct conn_probe_ctx {
struct conn_probe_ctx* next; /* linked list in nq->connectivity.probe_list */
struct UTUN_INSTANCE* instance;
struct NODEINFO_Q* nq;
uint8_t addr_type; // ADDR_TYPE_*
@ -248,7 +249,8 @@ static void conn_probe_finish(struct conn_probe_ctx* ctx, int ok) {
if (!ctx) return;
if (ctx->nq) {
struct NODE_CONNECTIVITY* c = &ctx->nq->connectivity;
if (c->probe_ctx == ctx) c->probe_ctx = NULL;
struct conn_probe_ctx** p = (struct conn_probe_ctx**)&c->probe_list;
while (*p) { if (*p == ctx) { *p = ctx->next; break; } p = &(*p)->next; }
switch (ctx->addr_type) {
case ADDR_TYPE_INTERFACE:
@ -352,7 +354,8 @@ void route_connectivity_probe_node(struct UTUN_INSTANCE* instance, struct NODEIN
ctx->timeout_ms = CONN_PROBE_TIMEOUT_MS;
ctx->best_across_sockets = 65535;
nq->connectivity.probe_ctx = ctx;
ctx->next = (struct conn_probe_ctx*)nq->connectivity.probe_list;
nq->connectivity.probe_list = ctx;
pend++;
conn_probe_start_series(ctx);
}
@ -411,7 +414,8 @@ void route_connectivity_probe_node(struct UTUN_INSTANCE* instance, struct NODEIN
ctx->timeout_ms = CONN_PROBE_TIMEOUT_MS;
ctx->best_across_sockets = 65535;
nq->connectivity.probe_ctx = ctx;
ctx->next = (struct conn_probe_ctx*)nq->connectivity.probe_list;
nq->connectivity.probe_list = ctx;
pend++;
conn_probe_start_series(ctx);
}
@ -433,10 +437,9 @@ void route_connectivity_cancel_node(struct UTUN_INSTANCE* instance, struct NODEI
if (!instance || !nq) return;
nq->connectivity.probe_status = PROBE_STATUS_NONE;
nq->connectivity.pending_count = 0;
if (nq->connectivity.probe_ctx) {
((struct conn_probe_ctx*)nq->connectivity.probe_ctx)->nq = NULL;
nq->connectivity.probe_ctx = NULL;
}
struct conn_probe_ctx* ctx = (struct conn_probe_ctx*)nq->connectivity.probe_list;
while (ctx) { ctx->nq = NULL; ctx = ctx->next; }
nq->connectivity.probe_list = NULL;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "connectivity probe cancelled for node %016llx", (unsigned long long)nq->node.node_id);
}

2
src/route_node.h

@ -56,7 +56,7 @@ struct NODE_CONNECTIVITY {
uint64_t nat_probe_time;
uint64_t real_probe_time;
uint64_t ping_req_time; // время последнего полученного ping request от этого узла (0.1ms tb)
void* probe_ctx; // активный conn_probe_ctx (для cancel)
void* probe_list; // linked list of active conn_probe_ctx (для cancel)
};
/**

Loading…
Cancel
Save