From da329d04794c56a87dacbeb60170032ff2882c29 Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 14 Sep 2026 13:49:12 +0300 Subject: [PATCH] =?UTF-8?q?merkle=5Fsync:=20ms=5Foutq=5Fdrain=5Fcb=20?= =?UTF-8?q?=E2=80=94=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D1=8F=D1=82?= =?UTF-8?q?=D1=8C=20e->len=20=D0=B4=D0=BE=20etcp=5Fsend=20(UAF);=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D1=82=D1=8C=20ownership=20etcp=5Fsend?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chat/merkle_sync.c | 3 ++- src/transport_layer/etcp_api.h | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/chat/merkle_sync.c b/src/chat/merkle_sync.c index e7cc3033..2ae5884f 100644 --- a/src/chat/merkle_sync.c +++ b/src/chat/merkle_sync.c @@ -316,10 +316,11 @@ static void ms_outq_drain_cb(struct ll_queue* q, void* arg) { if (e->dgram) u_free(e->dgram); queue_entry_free(e); } else { + uint16_t len = e->len; /* etcp_send может синхронно освободить e (ownership переходит в очередь) */ int r = etcp_send(conn, e); if (r != 0) { if (e->dgram) u_free(e->dgram); queue_entry_free(e); } DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: outq drain peer=%016llx len=%u rc=%d left=%d", - MS_ID, (unsigned long long)s->peer, e->len, r, queue_entry_count(s->out_q)); + MS_ID, (unsigned long long)s->peer, len, r, queue_entry_count(s->out_q)); } if (queue_entry_count(s->out_q) > 0 && conn && conn->send_input_q) queue_waiter_wait(conn->send_input_q, &s->waiter, ms_outq_drain_cb, s); diff --git a/src/transport_layer/etcp_api.h b/src/transport_layer/etcp_api.h index 75a780e2..a1cd7cb4 100644 --- a/src/transport_layer/etcp_api.h +++ b/src/transport_layer/etcp_api.h @@ -162,8 +162,11 @@ struct ETCP_BINDINGS { * @param entry Элемент очереди с данными для отправки * @return 0 при успехе, -1 при ошибке * - * @note Функция забирает ownership entry - вызывающий код не должен - * освобождать entry после вызова + * @note Функция забирает ownership entry — вызывающий код не должен + * ни освобождать, ни читать entry после вызова: если очередь + * normalizer'а пуста, entry освобождается СИНХРОННО внутри этого + * вызова (queue_data_put → callback → queue_entry_free). Любые + * нужные поля entry надо сохранять до etcp_send(). */ int etcp_send(struct ETCP_CONN* conn, struct ll_entry* entry);