Browse Source

fix: ASAN-detected UAFs and buffer overflows across 6 modules

- 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
chatgui
Evgeny 3 months ago
parent
commit
7d460ca156
  1. 3
      src/etcp.c
  2. 4
      src/etcp_connections.c
  3. 17
      src/proxy/socks_proxy.c
  4. 1
      src/proxy/socks_proxy.h
  5. 8
      src/proxy/tcp_proxy_server.c
  6. 6
      src/stcp_server.c
  7. 2
      tests/test_route6_lib.c

3
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,

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

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

1
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;

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

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

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

Loading…
Cancel
Save