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