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; if (!queue || !conn) return;
struct ll_entry* e = queue_data_get(queue); struct ll_entry* e = queue_data_get(queue);
if (!e) { queue_resume_callback(queue); return; } 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]; uint8_t id = e->dgram[0];
struct UTUN_INSTANCE* inst = conn->instance; 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]) if (inst->api_bindings.callbacks[id])
inst->api_bindings.callbacks[id](conn, e); inst->api_bindings.callbacks[id](conn, e);
else if (inst->api_bindings.callbacks[0]) else if (inst->api_bindings.callbacks[0])
inst->api_bindings.callbacks[0](conn, e); 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); 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; } if (!qe) { queue_dgram_free(entry); queue_entry_free(entry); return; }
*(uint32_t*)qe->data = seq; *(uint32_t*)qe->data = seq;
qe->dgram = u_malloc(pl_len); 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; qe->len = pl_len;
memcpy(qe->dgram, pl, 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) { if (ret != 0) {
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT client: etcp_route_send to provider %016llx failed", DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT client: etcp_route_send to provider %016llx failed",
(unsigned long long)tr->nat_via_node_id); (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) { if (send_ret != 0) {
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT provider: etcp_route_send back to node %016llx failed", DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT provider: etcp_route_send back to node %016llx failed",
(unsigned long long)entry->src_node_id); (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 // 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) { 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 (!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; return;
} }
struct UTUN_INSTANCE* inst = conn->instance; 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 nat_transport_ctx* tr = &inst->nat_tr;
struct eim_nat_ctx* ctx = &inst->nat; 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; uint64_t src_node_id;
memcpy(&src_node_id, entry->dgram + 1, 8); memcpy(&src_node_id, entry->dgram + 1, 8);

4
src/proxy/icmp_proxy.c

@ -173,7 +173,7 @@ drop:
// Сторона клиента: принять REPLY, доставить echo ответ в TUN // Сторона клиента: принять REPLY, доставить echo ответ в TUN
// ==================================================================== // ====================================================================
static void client_handle_reply(struct ETCP_CONN* conn, struct ll_entry* entry) { 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 src_ip;
uint32_t orig_src_ip; uint32_t orig_src_ip;
uint16_t echo_id, echo_seq; 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) { void icmp_proxy_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
if (!entry || !entry->dgram || entry->len < 2) { 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; return;
} }
uint8_t subcmd = entry->dgram[1]; uint8_t subcmd = entry->dgram[1];

4
src/proxy/udp_proxy.c

@ -114,7 +114,7 @@ drop:
// Сторона клиента: принять REPLY, доставить в TUN // Сторона клиента: принять REPLY, доставить в TUN
// ==================================================================== // ====================================================================
static void client_handle_reply(struct ETCP_CONN* conn, struct ll_entry* entry) { 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 // svc_id уже обработан диспетчером etcp_router
uint32_t src_ip, dst_ip; uint32_t src_ip, dst_ip;
uint16_t src_port, dst_port; 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) { void udp_proxy_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
if (!entry || !entry->dgram || entry->len < 2) { 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; return;
} }
uint8_t subcmd = entry->dgram[1]; 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) { static void srv_handler(struct ETCP_CONN* conn, struct ll_entry* entry) {
(void)conn; (void)conn;
if (!entry || !entry->dgram || entry->len < 10) { // svc_id(1) + subcmd(1) + seq(4) + data_len(4) 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; return;
} }
uint8_t subcmd = entry->dgram[1]; uint8_t subcmd = entry->dgram[1];
@ -123,7 +123,7 @@ static void srv_handler(struct ETCP_CONN* conn, struct ll_entry* entry) {
} else { } else {
fwd_rcvd++; fwd_rcvd++;
} }
queue_entry_free(entry); queue_dgram_free(entry); queue_dgram_free(entry); queue_entry_free(entry);
// Send reply back // Send reply back
if (!g_test_done && reply_sent < TOTAL_PACKETS) { 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++; } etcp_route_send(srv, client_node_id, re, 0); reply_sent++; }
} }
} else { } 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) { static void cli_handler(struct ETCP_CONN* conn, struct ll_entry* entry) {
(void)conn; (void)conn;
if (!entry || !entry->dgram || entry->len < 10) { 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; return;
} }
uint8_t subcmd = entry->dgram[1]; uint8_t subcmd = entry->dgram[1];
@ -166,7 +166,7 @@ static void cli_handler(struct ETCP_CONN* conn, struct ll_entry* entry) {
reply_rcvd++; reply_rcvd++;
} }
} }
queue_entry_free(entry); queue_dgram_free(entry); queue_dgram_free(entry); queue_entry_free(entry);
} }
// ======================== Loopback test (no ETCP) ======================== // ======================== Loopback test (no ETCP) ========================
@ -178,7 +178,7 @@ static void loop_handler(struct ETCP_CONN* conn, struct ll_entry* entry) {
loop_rcvd++; loop_rcvd++;
if (entry->dgram[1] == 0xAA && entry->dgram[2] == 0xBB && entry->dgram[3] == 0xCC) loop_ok = 1; 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) { static int test_loopback(void) {
@ -250,7 +250,7 @@ static void monitor(void* arg) {
struct ll_entry* e = queue_entry_new(0); 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 (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++; 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; return;
} }
if (entry->dgram[1] != rx.marker) { rx.errors++; } else { rx.delivered++; rx.last_seq = rx.expected_seq; rx.expected_seq++; } 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) { 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) { static void cli_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
(void)conn; (void)conn;
if (!entry || !entry->dgram || entry->len < ICMP_PROXY_HDR_SIZE + 1) { 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) { if (entry->dgram[1] == ICMP_PROXY_SUBCMD_REPLY) {
uint16_t rid, rseq; uint16_t rid, rseq;
@ -105,7 +105,7 @@ static void cli_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
g_done = -1; g_done = -1;
} }
} }
queue_entry_free(entry); queue_dgram_free(entry); queue_dgram_free(entry); queue_entry_free(entry);
} }
static void monitor(void* arg) { 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) { static void cli_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
(void)conn; (void)conn;
if (!entry || !entry->dgram || entry->len < UDP_PROXY_HDR_SIZE + 1) { 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 // 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; 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; g_done = -1;
} }
} }
queue_entry_free(entry); queue_dgram_free(entry); queue_dgram_free(entry); queue_entry_free(entry);
} }
static void monitor(void* arg) { static void monitor(void* arg) {

Loading…
Cancel
Save