From fa94735b84be0e9a77d78d49b454a972828ddd15 Mon Sep 17 00:00:00 2001 From: Andrew Cagney Date: Wed, 14 Jan 2026 18:31:31 +0900 Subject: [PATCH] helpers: work around NSS by joining helper threads Resolves: RHEL-73774 Signed-off-by: Andrew Cagney Signed-off-by: Daiki Ueno --- libreswan-5.3-helper-thread.patch | 97 +++++++++++++++++++++++++++++++ libreswan.spec | 1 + 2 files changed, 98 insertions(+) create mode 100644 libreswan-5.3-helper-thread.patch diff --git a/libreswan-5.3-helper-thread.patch b/libreswan-5.3-helper-thread.patch new file mode 100644 index 0000000..0693317 --- /dev/null +++ b/libreswan-5.3-helper-thread.patch @@ -0,0 +1,97 @@ +From eb31dda36d082e33749bc294d56ec493a094336d Mon Sep 17 00:00:00 2001 +From: Andrew Cagney +Date: Sun, 16 Nov 2025 10:33:53 -0500 +Subject: [PATCH] helpers: work around NSS by joining helper threads + +Much of the analysis and testing by Ondrej Moris + +NSS attaches stuff to the threads onexit queue that must +be run before the main thread exits (if it doesn't things +explode during shutdown). + +See: Race condition in helper_thread_stopped_callback() #2461 +See: PR_Cleanup() doesn't wait for pthread_create() threads +https://bugzilla.mozilla.org/show_bug.cgi?id=1992272 +--- + programs/pluto/server_pool.c | 42 +++++++++++++++++++++++++++++++----- + 1 file changed, 37 insertions(+), 5 deletions(-) + +diff --git a/programs/pluto/server_pool.c b/programs/pluto/server_pool.c +index 056a007301..5c7dc5e18d 100644 +--- a/programs/pluto/server_pool.c ++++ b/programs/pluto/server_pool.c +@@ -275,6 +275,22 @@ static void *helper_thread(void *arg) + dbg("helper %u: telling main thread that it is exiting", w->helper_id); + schedule_callback("helper stopped", deltatime(0), SOS_NOBODY, + helper_thread_stopped_callback, NULL); ++ /* ++ * Danger. This isn't the end. ++ * ++ * NSS still has stuff in thread-exit handlers to execute and ++ * there's no clean way of forcing its execution (and if it ++ * isn't allowed to run NSS crashes!). Hence, the main thread ++ * will need to wait for this thread to exit. ++ * ++ * But wait, there's more. The main thread also needs to keep ++ * the event loop running while these threads are exiting so ++ * ptread_join() needs to be called with care. ++ * ++ * See: Race condition in helper_thread_stopped_callback() #2461 ++ * See: PR_Cleanup() doesn't wait for pthread_create() threads ++ * https://bugzilla.mozilla.org/show_bug.cgi?id=1992272 ++ */ + return NULL; + } + +@@ -589,10 +605,6 @@ void start_server_helpers(uintmax_t nhelpers, struct logger *logger) + + /* + * Repeatedly nudge the helper threads until they all exit. +- * +- * Note that pthread_join() doesn't work here: an any-thread join may +- * end up joining an unrelated thread (for instance the CRL helper); +- * and a specific thread join may block waiting for the wrong thread. + */ + + static void (*server_helpers_stopped_callback)(void); +@@ -605,6 +617,17 @@ static void helper_thread_stopped_callback(const char *story UNUSED, + dbg("one helper thread exited, %u remaining", + helper_threads_started-helper_threads_stopped); + ++ /* ++ * Danger: ++ * ++ * Delay joining W.pid until all helper threads have exited. ++ * This way the event-loop is kept running. ++ * ++ * Even though W is on the exit path it still needs to execute ++ * NSS's thread exit code - who knows what that is doing and ++ * how long it will take - ++ */ ++ + /* wait for more? */ + if (helper_threads_started > helper_threads_stopped) { + /* poke threads waiting for work */ +@@ -612,9 +635,18 @@ static void helper_thread_stopped_callback(const char *story UNUSED, + return; + } + +- /* all done; cleanup */ ++ /* ++ * All done; cleanup ++ * ++ * All helper threads are on the exit war-path so, hopefully, ++ * this join will not block (but no telling what NSS did). ++ */ + for (unsigned h = 0; h < helper_threads_started; h++) { + struct helper_thread *w = &helper_threads[h]; ++ int e = pthread_join(w->pid, NULL); ++ if (e != 0) { ++ llog_errno(RC_LOG, w->logger, e, "WARNING: pthread_join() failed, "); ++ } + free_logger(&w->logger, HERE); + } + +-- +2.52.0 + diff --git a/libreswan.spec b/libreswan.spec index 3be8a47..9f34e8f 100644 --- a/libreswan.spec +++ b/libreswan.spec @@ -46,6 +46,7 @@ Source5: https://download.libreswan.org/cavs/ikev2.fax.bz2 Patch1: libreswan-4.15-ipsec_import.patch Patch2: libreswan-5.3-outstanding-ike-auth-crossing.patch +Patch3: libreswan-5.3-helper-thread.patch BuildRequires: audit-libs-devel BuildRequires: bison