From 14cbe0bf242319ec468b7b857030ef1095ad8af7 Mon Sep 17 00:00:00 2001 From: seantywork Date: Sun, 15 Feb 2026 09:40:49 +0000 Subject: [PATCH] whitelist: Fix deadlock when handling client disconnection Calling stream_t::destroy from the stream_t::on_read callback will block the thread in watcher_t::remove because the FD is currently "in callback". A similar issue was fixed in the lookip plugin with 961409b66858 ("lookip: Disconnect asynchronously to avoid dead-locking watcher unregistration"). Fixes: 85ebf6abd441 ("whitelist: Add error handling to socket reads and fix a memory leak") --- .../plugins/whitelist/whitelist_control.c | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/libcharon/plugins/whitelist/whitelist_control.c b/src/libcharon/plugins/whitelist/whitelist_control.c index 4aec53aee..37df7d936 100644 --- a/src/libcharon/plugins/whitelist/whitelist_control.c +++ b/src/libcharon/plugins/whitelist/whitelist_control.c @@ -25,6 +25,7 @@ #include #include +#include #include "whitelist_msg.h" @@ -101,6 +102,40 @@ typedef struct { size_t read; } whitelist_conn_t; +/** + * Information needed for async disconnect job. + */ +typedef struct { + whitelist_conn_t *conn; + stream_t *stream; +} disconnect_data_t; + +/** + * Asynchronous callback to disconnect client + */ +CALLBACK(disconnect_async, job_requeue_t, + disconnect_data_t *data) +{ + data->stream->destroy(data->stream); + free(data->conn); + return JOB_REQUEUE_NONE; +} + +/** + * Disconnect a connected client + */ +static void disconnect(whitelist_conn_t *conn, stream_t *stream) +{ + disconnect_data_t *data; + + INIT(data, + .conn = conn, + .stream = stream, + ); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create(disconnect_async, data, free, NULL)); +} + /** * Dispatch a received message */ @@ -127,8 +162,7 @@ CALLBACK(on_read, bool, { DBG1(DBG_CFG, "whitelist socket error: %s", strerror(errno)); } - stream->destroy(stream); - free(conn); + disconnect(conn, stream); return FALSE; } conn->read += len;