Browse Source

socks_proxy: defer conn free to fix UAF from synchronous write_queue flush

router-recv-conn-uaf
evgeny 2 weeks ago
parent
commit
21ec740d82
  1. 22
      src/proxy/socks_proxy.c
  2. 1
      src/proxy/socks_proxy.h

22
src/proxy/socks_proxy.c

@ -28,6 +28,8 @@ static void on_read_cb(struct ll_queue* q, void* arg);
static void on_fin_cb(struct tcp_conn* tc, void* arg);
static void on_error_cb(struct tcp_conn* tc, int err, void* arg);
static void on_closed_cb(struct tcp_conn* tc, void* arg);
static void socks_proxy_conn_free_deferred(void* arg);
static void socks_proxy_conn_free_soon(struct socks_proxy_conn* c);
static void tx_waiter_cb(struct ll_queue* q, void* arg);
static void tx_retry_timer_cb(void* arg);
static void socks_issue_dns(struct socks_proxy_conn* c, const char* host, uint8_t kind);
@ -119,8 +121,8 @@ static int write_to_client(struct socks_proxy_conn* c, const uint8_t* data, uint
}
memcpy(buf, data, len);
e->dgram = buf; e->len = len;
queue_data_put(c->tc->write_queue, e);
c->bytes_to_client += len;
queue_data_put(c->tc->write_queue, e);
return 0;
}
@ -556,7 +558,7 @@ static void on_error_cb(struct tcp_conn* tc, int err, void* arg) {
struct UTUN_INSTANCE* inst = c->inst;
uint64_t via = c->via_node_id;
uint32_t sid = c->stream_id;
socks_proxy_conn_free(c);
socks_proxy_conn_free_soon(c);
if (notify && inst) send_msg(inst, TOPO_GROUP_UTUN, via, TCP_PROXY_SUBCMD_ERROR, sid, NULL, 0, 1);
}
@ -565,7 +567,7 @@ static void on_closed_cb(struct tcp_conn* tc, void* arg) {
DEBUG_INFO(DEBUG_CATEGORY_PROXY, "socks_proxy: tcp closed sid=%08x state=%d fm_r=%d fm_l=%d rem_cl=%d bytes_client=%u bytes_exit=%u",
c->stream_id, c->state, tc->fin_remote, tc->fin_local, c->rem_closed, c->bytes_to_client, c->bytes_from_exit);
if (!c->close_sent && !c->close_pending) send_close(c);
socks_proxy_conn_free(c);
socks_proxy_conn_free_soon(c);
}
// ====================================================================
@ -627,8 +629,8 @@ int socks_proxy_handle_etcp(struct socks_proxy_conn** head, int* count,
uint8_t* buf = memory_pool_alloc(c->tc->data_pool);
if (e && buf) {
memcpy(buf, data, data_len); e->dgram = buf; e->len = (uint16_t)data_len;
queue_data_put(c->tc->write_queue, e);
c->bytes_to_client += (uint32_t)data_len;
queue_data_put(c->tc->write_queue, e);
} else {
DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "socks_proxy: handle_data alloc failed sid=%08x wq=%d bytes_in=%u bytes_out=%u",
stream_id, c->tc->write_queue->count, c->bytes_from_exit, c->bytes_to_client);
@ -665,10 +667,22 @@ int socks_proxy_handle_etcp(struct socks_proxy_conn** head, int* count,
return 1;
}
static void socks_proxy_conn_free_deferred(void* arg) {
struct socks_proxy_conn* c = (struct socks_proxy_conn*)arg;
c->free_soon_id = NULL;
socks_proxy_conn_free(c);
}
static void socks_proxy_conn_free_soon(struct socks_proxy_conn* c) {
if (!c || c->free_soon_id) return;
c->free_soon_id = uasync_call_soon(c->ua, c, socks_proxy_conn_free_deferred);
}
void socks_proxy_conn_free(struct socks_proxy_conn* c) {
if (!c) return;
if (c->freed) return;
c->freed = 1;
if (c->free_soon_id) { uasync_call_soon_cancel(c->ua, c->free_soon_id); c->free_soon_id = NULL; }
struct socks_proxy_conn** head = c->head; int* count = c->count;
DEBUG_INFO(DEBUG_CATEGORY_PROXY, "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

@ -52,6 +52,7 @@ struct socks_proxy_conn {
uint8_t is_http;
uint8_t state;
uint8_t freed;
void* free_soon_id; // handle отложенного освобождения (uasync_call_soon)
uint8_t buf[1024];
uint16_t buf_len;
uint8_t* tx_buf; // буфер при backpressure (retry в tx_waiter_cb)

Loading…
Cancel
Save