Browse Source

feat: hard crash on etcp_connection_close from callback chain

Added callbacks_running flag to ETCP_CONN:
- set to 1 before up_cbks / down_cbks / ready_cbks iteration
- reset to 0 after iteration completes
- etcp_connection_close checks flag and does intentional SIGSEGV
  with FATAL log message if called during callback chain

This catches illegal synchronous close from within callbacks
instead of producing cryptic UAF segfaults later.
topo_upd
Evgeny 3 months ago
parent
commit
f669254da3
  1. 13
      src/etcp.c
  2. 1
      src/etcp.h

13
src/etcp.c

@ -216,6 +216,7 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance, char* n
etcp->initialized=0;
etcp->links_up=0;
etcp->reset_done=0;
etcp->callbacks_running=0;
etcp->last_rr_link=NULL;
etcp->name = u_strdup(name);
// Initialize log_name with local node_id (peer will be updated later when known)
@ -270,14 +271,18 @@ 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);
etcp->callbacks_running = 1;
struct etcp_cbk_entry* cbe = etcp->up_cbks;
while (cbe) { struct etcp_cbk_entry* n = cbe->next; cbe->fn(etcp, cbe->arg); cbe = n; }
etcp->callbacks_running = 0;
}
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);
etcp->callbacks_running = 1;
struct etcp_cbk_entry* cbe = etcp->down_cbks;
while (cbe) { struct etcp_cbk_entry* n = cbe->next; cbe->fn(etcp, cbe->arg); cbe = n; }
etcp->callbacks_running = 0;
}
@ -286,6 +291,12 @@ void etcp_connection_close(struct ETCP_CONN* etcp) {
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
if (!etcp) return;
if (etcp->callbacks_running) {
DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "[%s] FATAL: etcp_connection_close called from inside callback chain — SEGFAULTING to show backtrace",
etcp->log_name);
*(volatile int*)0 = 0;
}
if (etcp->links_up!=0) {
etcp->links_up=0;
etcp_on_down(etcp);
@ -541,8 +552,10 @@ void etcp_conn_ready(struct ETCP_CONN* conn) {
etcp_metrics_start_timer(conn);
// Вызываем callback если установлен
conn->callbacks_running = 1;
{ 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);
conn->callbacks_running = 0;
}

1
src/etcp.h

@ -226,6 +226,7 @@ struct ETCP_CONN {
uint8_t tx_state; // 0 - n/a, 1 - data_wait (queues empty), 2 - link_wait (link busy)
uint8_t links_up; // 0 - канал не готов для передачи, 1 - канал готов для передачи (хотя бы один линк не down)
uint8_t reset_done; // 0 - рукопожатие не завершено (реинит разрешён), 1 - соединение стабильно (реинит заблокирован)
uint8_t callbacks_running; // 1 - внутри итерации колбэк-цепочек, etcp_connection_close запрещён
// Callback chains for ready/up/down notifications
struct etcp_cbk_entry* ready_cbks; // цепочка callback'ов при готовности соединения

Loading…
Cancel
Save