From 7d460ca156d22d0f7b8ed7910a074dedab781d86 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Thu, 2 Jul 2026 13:35:22 +0300 Subject: [PATCH] fix: ASAN-detected UAFs and buffer overflows across 6 modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - etcp_connections: fix link leak & UAF in etcp_socket_remove — remove_link inside etcp_link_close shifts array, skip NULL set and i++ - stcp_server: fix UAF in stcp_conn_process_recv — defer free via uasync_call_soon after stcp_conn_do_close - etcp: save pkt_len before queue_data_put to output_queue (callback may free entry synchronously) - socks_proxy: add pool bounds check before memcpy, UINT16_MAX truncation guard, freed flag - tcp_proxy_server: reorder cleanup (cancel waiters before tcp_conn_destroy), UINT16_MAX guard - test_route6_lib: increase nodes[] array to STRESS_NODES + STRESS_OPS --- src/etcp.c | 3 ++- src/etcp_connections.c | 4 +--- src/proxy/socks_proxy.c | 17 +++++++++++++++++ src/proxy/socks_proxy.h | 1 + src/proxy/tcp_proxy_server.c | 8 ++++++-- src/stcp_server.c | 6 +++++- tests/test_route6_lib.c | 2 +- 7 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/etcp.c b/src/etcp.c index 4bab999e..256bf5d7 100644 --- a/src/etcp.c +++ b/src/etcp.c @@ -1182,8 +1182,9 @@ void etcp_output_try_assembly(struct ETCP_CONN* etcp) { // Add to output_queue using the same ETCP_FRAGMENT structure DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "[%s] moving packet id=%u to output_queue (qlen=%d)", etcp->log_name, next_expected_id, etcp->output_queue->count); + uint16_t pkt_len = rx_pkt->ll.len; if (queue_data_put(etcp->output_queue, (struct ll_entry*)rx_pkt) == 0) { - delivered_bytes += rx_pkt->ll.len; + delivered_bytes += pkt_len; delivered_count++; } else { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[%s] failed to add packet id=%u to output_queue", etcp->log_name, diff --git a/src/etcp_connections.c b/src/etcp_connections.c index a723e40f..036ed52a 100644 --- a/src/etcp_connections.c +++ b/src/etcp_connections.c @@ -740,9 +740,7 @@ void etcp_socket_remove(struct ETCP_SOCKET* conn) { size_t i = 0; while (i < conn->num_channels) { struct ETCP_LINK* l = conn->links[i]; - etcp_link_close(l); - conn->links[i] = NULL; // обнулить после — etcp_link_close обращается к массиву через remove_link - i++; + etcp_link_close(l); // remove_link inside shifts elements left → next at same i } u_free(conn->links); diff --git a/src/proxy/socks_proxy.c b/src/proxy/socks_proxy.c index c8f8d02f..86fb6b4c 100644 --- a/src/proxy/socks_proxy.c +++ b/src/proxy/socks_proxy.c @@ -55,6 +55,10 @@ static int send_msg(struct UTUN_INSTANCE* inst, uint64_t dst, uint8_t subcmd, ui e->dgram[1] = subcmd; memcpy(e->dgram + 2, &sid, 4); if (len > 0) memcpy(e->dgram + TCP_PROXY_HDR_SIZE, data, len); + if (TCP_PROXY_HDR_SIZE + len > UINT16_MAX) { + DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "socks_proxy: msg too large len=%zu subcmd=%02x", len, subcmd); + queue_dgram_free(e); queue_entry_free(e); return -1; + } e->len = (uint16_t)(TCP_PROXY_HDR_SIZE + len); return etcp_route_send(inst, dst, e, force); } @@ -97,6 +101,12 @@ static int write_to_client(struct socks_proxy_conn* c, const uint8_t* data, uint if (e) queue_entry_free(e); if (buf) memory_pool_free(c->tc->data_pool, buf); return -1; } + if (len > c->tc->data_pool->object_size) { + DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "socks_proxy: write_to_client len=%u > pool_sz=%zu sid=%08x", + len, c->tc->data_pool->object_size, c->stream_id); + queue_entry_free(e); memory_pool_free(c->tc->data_pool, buf); + return -1; + } memcpy(buf, data, len); e->dgram = buf; e->len = len; queue_data_put(c->tc->write_queue, e); @@ -361,6 +371,11 @@ int socks_proxy_handle_etcp(struct socks_proxy_conn** head, int* count, if (subcmd == TCP_PROXY_SUBCMD_DATA) { if (data_len > 0) { + if (data_len > c->tc->data_pool->object_size) { + DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "socks_proxy: data_len=%zu > pool_sz=%zu, dropping sid=%08x", + data_len, c->tc->data_pool->object_size, stream_id); + return 1; + } struct ll_entry* e = queue_entry_new_from_pool(c->tc->entry_pool); uint8_t* buf = memory_pool_alloc(c->tc->data_pool); if (e && buf) { @@ -403,6 +418,8 @@ int socks_proxy_handle_etcp(struct socks_proxy_conn** head, int* count, void socks_proxy_conn_free(struct socks_proxy_conn* c) { if (!c) return; + if (c->freed) return; + c->freed = 1; struct socks_proxy_conn** head = c->head; int* count = c->count; DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "socks_proxy: FREE sid=%08x state=%d total=%d", c->stream_id, c->state, count ? *count : 0); if (c->close_pending && c->inst) { diff --git a/src/proxy/socks_proxy.h b/src/proxy/socks_proxy.h index c0acfd74..33acded8 100644 --- a/src/proxy/socks_proxy.h +++ b/src/proxy/socks_proxy.h @@ -42,6 +42,7 @@ struct socks_proxy_conn { uint8_t close_pending; uint8_t is_http; uint8_t state; + uint8_t freed; uint8_t buf[1024]; uint16_t buf_len; struct queue_waiter_handle tx_waiter; diff --git a/src/proxy/tcp_proxy_server.c b/src/proxy/tcp_proxy_server.c index 47d7eda2..0b0d61f6 100644 --- a/src/proxy/tcp_proxy_server.c +++ b/src/proxy/tcp_proxy_server.c @@ -57,6 +57,10 @@ static int send_msg(struct UTUN_INSTANCE* inst, uint64_t dst, uint8_t subcmd, e->dgram[1] = subcmd; memcpy(e->dgram + 2, &sid, 4); if (len > 0) memcpy(e->dgram + TCP_PROXY_HDR_SIZE, data, len); + if (TCP_PROXY_HDR_SIZE + len > UINT16_MAX) { + DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "tcp_proxy_server: msg too large len=%zu subcmd=%02x", len, subcmd); + queue_dgram_free(e); queue_entry_free(e); return -1; + } e->len = TCP_PROXY_HDR_SIZE + len; return etcp_route_send(inst, dst, e, force); } @@ -253,10 +257,10 @@ void tcp_proxy_server_conn_free(struct tcp_proxy_server_conn* rc) { struct tcp_proxy_server_conn** prev = &rc->ctx->conns; while (*prev) { if (*prev == rc) { *prev = rc->next; rc->ctx->conn_count--; break; } prev = &(*prev)->next; } } - if (rc->tc) { tcp_conn_destroy(rc->tc); rc->tc = NULL; } + if (rc->ctx && rc->ctx->inst) etcp_router_cancel_send_ready(rc->ctx->inst, rc->peer_node_id, ETCP_ID_TCP_PROXY_CLIENT, &rc->pause_waiter); if (rc->close_timer) { uasync_cancel_timeout(rc->ua, rc->close_timer); rc->close_timer = NULL; } if (rc->diag_timer) { uasync_cancel_timeout(rc->ua, rc->diag_timer); rc->diag_timer = NULL; } - if (rc->ctx && rc->ctx->inst) etcp_router_cancel_send_ready(rc->ctx->inst, rc->peer_node_id, ETCP_ID_TCP_PROXY_CLIENT, &rc->pause_waiter); + if (rc->tc) { tcp_conn_destroy(rc->tc); rc->tc = NULL; } DEBUG_DEBUG(DEBUG_CATEGORY_SOCKET, "SOCK:FREE u_free rc=%p", (void*)rc); u_free(rc); } diff --git a/src/stcp_server.c b/src/stcp_server.c index 348bf81e..5c58d2a3 100644 --- a/src/stcp_server.c +++ b/src/stcp_server.c @@ -72,6 +72,10 @@ static int stcp_decrypt_and_check(uint8_t *plaintext, size_t plaintext_len, return 0; } +static void stcp_conn_deferred_free(void* arg) { + u_free((struct stcp_conn*)arg); +} + static void stcp_conn_do_close(struct stcp_conn *c, int err) { if (c->state == STCP_STATE_CLOSED || c->state == STCP_STATE_ERROR) return; int prev = c->state; @@ -82,7 +86,7 @@ static void stcp_conn_do_close(struct stcp_conn *c, int err) { if (c->send_buf) { u_free(c->send_buf); c->send_buf = NULL; c->send_len = 0; } DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "stcp_conn closed is_server=%d prev_state=%d err=%d", c->is_server, prev, err); if (c->on_close) { void (*cb)(struct stcp_conn*, int, void*) = c->on_close; cb(c, err, c->close_arg); } - else if (prev == STCP_STATE_HS_SERVER_WAIT) { sc_stream_cleanup(&c->stream_send); sc_stream_cleanup(&c->stream_recv); if (c->allocated) u_free(c); } + else if (prev == STCP_STATE_HS_SERVER_WAIT) { sc_stream_cleanup(&c->stream_send); sc_stream_cleanup(&c->stream_recv); if (c->allocated) uasync_call_soon(c->ua, c, stcp_conn_deferred_free); } } static void stcp_conn_send_message(struct stcp_conn *c, const uint8_t *data, size_t len) { diff --git a/tests/test_route6_lib.c b/tests/test_route6_lib.c index c6e7a5ba..279c7058 100644 --- a/tests/test_route6_lib.c +++ b/tests/test_route6_lib.c @@ -285,7 +285,7 @@ static void test_stress(void) { struct saved_route sr[MAX_SAVED]; int nsr = 0; - struct NODEINFO_Q *nodes[STRESS_NODES]; + struct NODEINFO_Q *nodes[STRESS_NODES + STRESS_OPS]; // create nodes with random subnets int n_created = 0;