Browse Source

fix: segfault in callback chain iteration — save next before invoke

In etcp_conn_ready / etcp_on_up / etcp_on_down / etcp_connection_create /
tcp_server_on_link, callback chains were iterated with:
  while (cbe) { cbe->fn(...); cbe = cbe->next; }
If the callback removes itself from the chain (e.g. ca_ready_cb calls
etcp_conn_remove_ready_cbk which u_free's the entry), cbe->next reads
freed memory → SIGSEGV.

Fixed by saving next pointer before invoking the callback:
  while (cbe) { n = cbe->next; cbe->fn(...); cbe = n; }
topo_upd
Evgeny 3 months ago
parent
commit
0912499309
  1. 8
      src/etcp.c
  2. 4
      src/etcp_connections.c

8
src/etcp.c

@ -261,7 +261,7 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance, char* n
// Вызываем callback для нового соединения если установлен
if (instance) {
struct etcp_cbk_entry* cbe = instance->new_conn_cbks;
while (cbe) { cbe->fn(etcp, cbe->arg); cbe = cbe->next; }
while (cbe) { struct etcp_cbk_entry* n = cbe->next; cbe->fn(etcp, cbe->arg); cbe = n; }
}
return etcp;
@ -271,13 +271,13 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance, char* n
static void etcp_on_up(struct ETCP_CONN* etcp) {
DEBUG_WARN(DEBUG_CATEGORY_BGP, "[%s] UP links_up=%d initialized=%d", etcp->log_name, etcp->links_up, etcp->initialized);
struct etcp_cbk_entry* cbe = etcp->up_cbks;
while (cbe) { cbe->fn(etcp, cbe->arg); cbe = cbe->next; }
while (cbe) { struct etcp_cbk_entry* n = cbe->next; cbe->fn(etcp, cbe->arg); cbe = n; }
}
static void etcp_on_down(struct ETCP_CONN* etcp) {
DEBUG_WARN(DEBUG_CATEGORY_BGP, "[%s] DOWN links_up=%d", etcp->log_name, etcp->links_up);
struct etcp_cbk_entry* cbe = etcp->down_cbks;
while (cbe) { cbe->fn(etcp, cbe->arg); cbe = cbe->next; }
while (cbe) { struct etcp_cbk_entry* n = cbe->next; cbe->fn(etcp, cbe->arg); cbe = n; }
}
@ -541,7 +541,7 @@ void etcp_conn_ready(struct ETCP_CONN* conn) {
etcp_metrics_start_timer(conn);
// Вызываем callback если установлен
{ struct etcp_cbk_entry* cbe = conn->ready_cbks; while (cbe) { cbe->fn(conn, cbe->arg); cbe = cbe->next; } }
{ struct etcp_cbk_entry* cbe = conn->ready_cbks; while (cbe) { struct etcp_cbk_entry* n = cbe->next; cbe->fn(conn, cbe->arg); cbe = n; } }
if (conn->links_up) etcp_on_up(conn);
}

4
src/etcp_connections.c

@ -41,8 +41,8 @@ static void tcp_server_on_link(struct stcp_link *link, void *arg) {
inst->connections = conn;
inst->connections_count++;
struct etcp_cbk_entry* cbe = inst->new_conn_cbks;
while (cbe) { cbe->fn(conn, cbe->arg); cbe = cbe->next; }
{ struct etcp_cbk_entry* rcb = conn->ready_cbks; while (rcb) { rcb->fn(conn, rcb->arg); rcb = rcb->next; } }
while (cbe) { struct etcp_cbk_entry* n = cbe->next; cbe->fn(conn, cbe->arg); cbe = n; }
{ struct etcp_cbk_entry* rcb = conn->ready_cbks; while (rcb) { struct etcp_cbk_entry* n = rcb->next; rcb->fn(conn, rcb->arg); rcb = n; } }
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "TCP server new conn=%p total=%d", (void*)conn, inst->connections_count);
}

Loading…
Cancel
Save