fix: use-after-free in pkt_normalizer + ll_queue waiter cancel + uasync gen counter for epoll fd-reuse
- pkt_normalizer: save recvpart->len before queue_data_put (may free synchronously) - ll_queue: save uasync_call_soon handle in queue_waiter_handle, cancel on free - uasync: generation counter in epoll data.u64 to skip stale events after fd reuse - uasync: keep fd_to_index mapping after socket_array_remove for inactive nodes - test: test_uasync_socket_race — 4 children × 200 iterations, currently flaky
This commit is contained in:
1 parent
a01e2f0899
commit
ccdbab95a8
6 files changed
+228
-59
No files matched your search
+8
-4
@@ -130,11 +130,11 @@ void queue_free(struct ll_queue* q) {
|
||||
// ВАЖНО: Не освобождаем элементы в очереди - они должны быть извлечены отдельно
|
||||
// Это упрощает архитектуру и предотвращает double-u_free
|
||||
|
||||
// Освободить список waiters (сбросить handle->internal)
|
||||
// Освободить список waiters (сбросить handle->internal, отменить отложенные вызовы)
|
||||
struct queue_waiter* w = q->waiter_head;
|
||||
while (w) {
|
||||
struct queue_waiter* next = w->next;
|
||||
if (w->handle) w->handle->internal = NULL;
|
||||
if (w->handle) { w->handle->internal = NULL; if (w->handle->call_soon_id) { uasync_call_soon_cancel(q->ua, w->handle->call_soon_id); w->handle->call_soon_id = NULL; } }
|
||||
u_free(w);
|
||||
w = next;
|
||||
}
|
||||
@@ -305,14 +305,17 @@ static uint32_t make_hash(const void* data, uint16_t len) {// алгоритм F
|
||||
|
||||
static void waiter_defer_cb(void* arg) {
|
||||
struct queue_waiter_handle* h = (struct queue_waiter_handle*)arg;
|
||||
h->defer_cb(h->defer_q, h->defer_arg);
|
||||
h->call_soon_id = NULL;
|
||||
if (h->defer_cb) h->defer_cb(h->defer_q, h->defer_arg);
|
||||
else DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "waiter_defer_cb: NULL callback (stale?) q=%p", (void*)h->defer_q);
|
||||
}
|
||||
|
||||
static inline void queue_waiter_call(struct ll_queue* q, queue_threshold_callback_fn cb, void* arg,
|
||||
struct queue_waiter_handle* h) {
|
||||
if (q->waiter_defer) {
|
||||
if (h->call_soon_id) { DEBUG_WARN(DEBUG_CATEGORY_LL_QUEUE, "queue_waiter_call: overwriting existing call_soon_id=%p", h->call_soon_id); uasync_call_soon_cancel(q->ua, h->call_soon_id); }
|
||||
h->defer_q = q; h->defer_cb = cb; h->defer_arg = arg;
|
||||
uasync_call_soon(q->ua, h, waiter_defer_cb);
|
||||
h->call_soon_id = uasync_call_soon(q->ua, h, waiter_defer_cb);
|
||||
} else {
|
||||
cb(q, arg);
|
||||
}
|
||||
@@ -692,6 +695,7 @@ int queue_waiter_wait(struct ll_queue* q, struct queue_waiter_handle* h,
|
||||
|
||||
void queue_waiter_cancel(struct ll_queue* q, struct queue_waiter_handle* h) {
|
||||
if (!q || !h || !h->internal) return;
|
||||
if (h->call_soon_id) { uasync_call_soon_cancel(q->ua, h->call_soon_id); h->call_soon_id = NULL; }
|
||||
|
||||
struct queue_waiter* waiter = h->internal;
|
||||
struct queue_waiter* prev = NULL;
|
||||
|
||||
Reference in new issue
Block a user