Commit 14cbe0bf24 for strongswan.org
commit 14cbe0bf242319ec468b7b857030ef1095ad8af7
Author: seantywork <seantywork@gmail.com>
Date: Sun Feb 15 09:40:49 2026 +0000
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")
diff --git a/src/libcharon/plugins/whitelist/whitelist_control.c b/src/libcharon/plugins/whitelist/whitelist_control.c
index 4aec53aeef..37df7d9361 100644
--- a/src/libcharon/plugins/whitelist/whitelist_control.c
+++ b/src/libcharon/plugins/whitelist/whitelist_control.c
@@ -25,6 +25,7 @@
#include <daemon.h>
#include <collections/linked_list.h>
+#include <processing/jobs/callback_job.h>
#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;