9 changed files with 162 additions and 0 deletions
@ -0,0 +1,71 @@
|
||||
// call_ring.c — статический кольцевой трейс вызовов (диагностика UAF в teardown)
|
||||
#include "call_ring.h" |
||||
#include <stdio.h> |
||||
|
||||
#if defined(_WIN32) |
||||
#include <io.h> |
||||
#else |
||||
#include <unistd.h> |
||||
#include <fcntl.h> |
||||
#endif |
||||
|
||||
callring_entry_t g_callring[CALLRING_SIZE]; |
||||
uint32_t g_callring_idx = 0; |
||||
|
||||
static const char *cr_name(uint32_t code) { |
||||
switch (code) { |
||||
case CR_LINK_NEW: return "LINK_NEW"; |
||||
case CR_LINK_CLOSE_IN: return "LINK_CLOSE_IN"; |
||||
case CR_LINK_CLOSE_TCP: return "LINK_CLOSE_TCP"; |
||||
case CR_LINK_CLOSE_FREE: return "LINK_CLOSE_FREE"; |
||||
case CR_TCPCB_IN: return "TCPCB_IN"; |
||||
case CR_TCPCB_FREE: return "TCPCB_FREE"; |
||||
case CR_SRV_ONLINK: return "SRV_ONLINK"; |
||||
case CR_SLINK_CLOSE: return "SLINK_CLOSE"; |
||||
case CR_SLINK_IMPL: return "SLINK_IMPL"; |
||||
case CR_SLINK_ONSTCP: return "SLINK_ONSTCP"; |
||||
case CR_CONN_SETONCLOSE: return "CONN_SETONCLOSE"; |
||||
case CR_CONN_DOCLOSE_IN: return "CONN_DOCLOSE_IN"; |
||||
case CR_CONN_DOCLOSE_CB: return "CONN_DOCLOSE_CB"; |
||||
case CR_CONN_FREE: return "CONN_FREE"; |
||||
case CR_CCLOSE_IN: return "CCLOSE_IN"; |
||||
case CR_CFREE_RES: return "CFREE_RES"; |
||||
case CR_NCD_DEFER: return "NCD_DEFER"; |
||||
default: return "?"; |
||||
} |
||||
} |
||||
|
||||
/* Дамп последних записей кольцевого буфера в /tmp/utun_callring.<pid> (и stderr
|
||||
* при ошибке). Форматирование только через snprintf в стековый буфер — в |
||||
* обработчике сигнала не выделяет память. */ |
||||
void callring_dump(void) { |
||||
char buf[192]; |
||||
int fd = -1; |
||||
|
||||
#if defined(_WIN32) |
||||
fd = 2; |
||||
#else |
||||
{ |
||||
char path[96]; |
||||
snprintf(path, sizeof(path), "/tmp/utun_callring.%d", (int)getpid()); |
||||
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); |
||||
} |
||||
if (fd < 0) fd = 2; |
||||
#endif |
||||
|
||||
int n = snprintf(buf, sizeof(buf), "callring dump idx=%u\n", g_callring_idx); |
||||
if (n > 0) { ssize_t w = write(fd, buf, (size_t)n); (void)w; } |
||||
|
||||
uint32_t total = g_callring_idx < CALLRING_SIZE ? g_callring_idx : CALLRING_SIZE; |
||||
uint32_t start = g_callring_idx >= CALLRING_SIZE ? g_callring_idx - CALLRING_SIZE : 0; |
||||
for (uint32_t k = 0; k < total; k++) { |
||||
const callring_entry_t *e = &g_callring[(start + k) % CALLRING_SIZE]; |
||||
n = snprintf(buf, sizeof(buf), "%s a=0x%lx b=0x%lx\n", cr_name(e->code), |
||||
(unsigned long)e->a, (unsigned long)e->b); |
||||
if (n > 0) { ssize_t w = write(fd, buf, (size_t)n); (void)w; } |
||||
} |
||||
|
||||
#if !defined(_WIN32) |
||||
if (fd != 2) close(fd); |
||||
#endif |
||||
} |
||||
@ -0,0 +1,52 @@
|
||||
// call_ring.h — статический кольцевой трейс вызовов (диагностика UAF в teardown)
|
||||
//
|
||||
// Каждая контрольная точка пишет в общий кольцевой буфер номер (code) и два
|
||||
// указателя-объекта (a, b). По последовательности записей + адресам из core-дампа
|
||||
// можно размотать, кто кого вызвал и кто освободил линк без обнуления обратных ссылок.
|
||||
#ifndef CALL_RING_H |
||||
#define CALL_RING_H |
||||
|
||||
#include <stdint.h> |
||||
#include <stddef.h> |
||||
|
||||
#define CALLRING_SIZE 1024 |
||||
|
||||
typedef struct { |
||||
uint32_t code; // код контрольной точки (число)
|
||||
uintptr_t a; // объект 1 (link/sl/conn/etcp)
|
||||
uintptr_t b; // объект 2 (close_arg/tcp_link/etcp_link)
|
||||
} callring_entry_t; |
||||
|
||||
extern callring_entry_t g_callring[CALLRING_SIZE]; |
||||
extern uint32_t g_callring_idx; |
||||
|
||||
static inline void callring_put(uint32_t code, uintptr_t a, uintptr_t b) { |
||||
callring_entry_t *e = &g_callring[g_callring_idx % CALLRING_SIZE]; |
||||
e->code = code; e->a = a; e->b = b; |
||||
g_callring_idx++; |
||||
} |
||||
|
||||
void callring_dump(void); |
||||
|
||||
/* коды контрольных точек */ |
||||
enum { |
||||
CR_LINK_NEW = 1, /* etcp_link_new → a=link b=etcp */ |
||||
CR_LINK_CLOSE_IN = 2, /* etcp_link_close вход → a=link b=etcp */ |
||||
CR_LINK_CLOSE_TCP = 3, /* etcp_link_close is_tcp-ветка → a=tcp_link b=link */ |
||||
CR_LINK_CLOSE_FREE = 4, /* etcp_link_close перед u_free → a=link */ |
||||
CR_TCPCB_IN = 5, /* tcp_link_close_cb вход → a=sl b=arg(link) */ |
||||
CR_TCPCB_FREE = 6, /* tcp_link_close_cb → etcp_link_close → a=link */ |
||||
CR_SRV_ONLINK = 7, /* tcp_server_on_link → a=tlink b=sl */ |
||||
CR_SLINK_CLOSE = 10, /* stcp_link_close → a=sl b=etcp_link */ |
||||
CR_SLINK_IMPL = 11, /* stcp_link_close_impl → a=sl b=conn */ |
||||
CR_SLINK_ONSTCP = 12, /* stcp_link_on_stcp_close → a=conn b=arg(sl) */ |
||||
CR_CONN_SETONCLOSE = 20, /* stcp_conn_set_on_close → a=c b=arg */ |
||||
CR_CONN_DOCLOSE_IN = 21, /* stcp_conn_do_close вход → a=c */ |
||||
CR_CONN_DOCLOSE_CB = 22, /* stcp_conn_do_close перед cb → a=c b=close_arg */ |
||||
CR_CONN_FREE = 23, /* stcp_conn_free → a=c */ |
||||
CR_CCLOSE_IN = 30, /* etcp_connection_close вход → a=etcp */ |
||||
CR_CFREE_RES = 31, /* etcp_connection_free_resources → a=etcp */ |
||||
CR_NCD_DEFER = 40, /* ncd_deferred_close_conn → a=conn */ |
||||
}; |
||||
|
||||
#endif /* CALL_RING_H */ |
||||
Loading…
Reference in new issue