Browse Source

stcp: закрывать принятые коннекты в stcp_server_destroy (UAF server_tlink->conn после tcp_socket_remove)

v2
evgeny 3 weeks ago
parent
commit
5633903be0
  1. 3
      src/transport_layer/stcp.c
  2. 7
      src/transport_layer/stcp.h
  3. 18
      src/transport_layer/stcp_server.c

3
src/transport_layer/stcp.c

@ -27,6 +27,7 @@ void stcp_conn_set_on_close(struct stcp_conn *c, void (*cb)(struct stcp_conn *co
void stcp_conn_free(struct stcp_conn *c) {
if (!c) return;
stcp_server_remove_conn(c);
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_conn_free: c=%p sock=%d sock_id=%p recv_buf=%p state=%d allocated=%d",
(void*)c, (int)c->sock, (void*)c->socket_id, (void*)c->recv_buf, (int)c->state, (int)c->allocated);
if (c->socket_id) { uasync_remove_socket_t(c->ua, c->sock); c->socket_id = NULL; }
@ -292,6 +293,8 @@ void stcp_conn_do_close(struct stcp_conn *c, int err) {
int prev = c->state;
c->state = STCP_STATE_CLOSED;
stcp_server_remove_conn(c);
if (c->hs_timer) { uasync_cancel_timeout(c->ua, c->hs_timer); c->hs_timer = NULL; }
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_conn close is_server=%d prev_state=%d err=%d sock=%d", c->is_server, prev, err, (int)c->sock);

7
src/transport_layer/stcp.h

@ -18,6 +18,7 @@ extern "C" {
struct UTUN_INSTANCE;
struct ETCP_CONN;
struct stcp_server;
typedef void (*stcp_ping_cb)(int success, uint16_t rtt, void *arg);
@ -143,6 +144,9 @@ struct stcp_conn {
uint16_t recv_msg_size; // stream: size from decoded header
void (*recv_on_chunk)(struct stcp_conn *c, uint8_t *data, size_t len);
uint8_t rx_paused; // reading paused due to rx_queue overflow
struct stcp_server *srv; // владеющий сервер (accept-сторона), NULL для клиентских коннектов
struct stcp_conn *srv_next; // звено в списке принятых коннектов сервера
};
void stcp_conn_free(struct stcp_conn *c);
@ -175,6 +179,9 @@ void stcp_recv_try(struct stcp_conn *c);
// unified close: closes socket, frees buffers, calls on_close. does NOT clean streams (stcp_conn_free does)
void stcp_conn_do_close(struct stcp_conn *c, int err);
// снимает принятый коннект из списка владеющего сервера (реализация в stcp_server.c)
void stcp_server_remove_conn(struct stcp_conn *c);
// handshake timeout callback (for use with uasync_set_timeout)
void hs_timeout_cb(void *arg);

18
src/transport_layer/stcp_server.c

@ -36,8 +36,18 @@ struct stcp_server {
uint8_t reality_enabled;
struct reality_server_config reality_srv;
char reality_dest[REALITY_DEST_MAX];
struct stcp_conn *conns; // список принятых (accept) коннектов — закрываются при destroy
};
void stcp_server_remove_conn(struct stcp_conn *c) {
if (!c || !c->srv) return;
struct stcp_conn **pp = &c->srv->conns;
while (*pp && *pp != c) pp = &(*pp)->srv_next;
if (*pp) *pp = c->srv_next;
c->srv = NULL;
}
static void server_accept_cb(socket_t sock, void *arg);
static void server_conn_read_cb(socket_t sock, void *arg);
static void server_hs_phase1_cb(struct stcp_conn *c, uint8_t *data, size_t len);
@ -290,6 +300,10 @@ static void server_accept_cb(socket_t listen_sock, void *arg) {
stcp_recv_set(c, SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_CLIENT, 0, server_hs_phase1_cb);
}
c->hs_timer = uasync_set_timeout(c->ua, STCP_HS_TIMEOUT, c, hs_timeout_cb, "stcp_hs");
c->srv = srv;
c->srv_next = srv->conns;
srv->conns = c;
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_server: accepted connection fd=%d", (int)cli_sock);
}
@ -356,6 +370,10 @@ void stcp_server_destroy(struct stcp_server *srv) {
if (!srv) return;
if (srv->listen_id) uasync_remove_socket_t(srv->ua, srv->listen_sock);
if (srv->listen_sock != SOCKET_INVALID) socket_close_wrapper(srv->listen_sock);
while (srv->conns) {
struct stcp_conn *c = srv->conns;
stcp_conn_do_close(c, 0); // снимает c из списка (c->srv) и каскадно закрывает серверный ETCP_LINK
}
u_free(srv);
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_server destroyed");
}

Loading…
Cancel
Save