Browse Source

fix: swap queue_entry_free/queue_dgram_free order in 27 places — prevents UAF when dgram_free accesses freed entry

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
chatgui
Evgeny 3 months ago
parent
commit
42d96f118d
  1. 6
      src/etcp_api.c
  2. 2
      src/etcp_router.c
  3. 10
      src/nat_transport.c
  4. 4
      src/proxy/icmp_proxy.c
  5. 4
      src/proxy/udp_proxy.c
  6. 14
      tests/test_etcp_router.c
  7. 2
      tests/test_etcp_router_unit.c
  8. 4
      tests/test_icmp_proxy.c
  9. 4
      tests/test_udp_proxy.c

6
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);
}

2
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);

10
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);

4
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];

4
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];

14
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); }
}
}

2
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) {

4
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) {

4
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) {

Loading…
Cancel
Save