Commit 7c852ee376 for strongswan.org
commit 7c852ee376f9e1dcc248f22005f5241f9cdc2661
Author: Tobias Brunner <tobias@strongswan.org>
Date: Fri Oct 30 08:36:05 2026 +0100
openssl: Unload providers when used via fuzzers
While we usually don't do this (due to atexit() handler conflicts in our
programs) and just suppress the leaks, this doesn't work when running the
fuzzers on OSS-Fuzz as we can't control LSAN_OPTIONS, and injecting the
suppressions file into the fuzzers via `__lsan_default_options` also
seems like a hack.
It did require adding `atexit()` handlers to the fuzzers that initialize
via `LLVMFuzzerInitialize()` as they never call `library_deinit()`
otherwise. The important thing there is to register the handler(s) after
the plugins have been loaded and OpenSSL registered its handler.
diff --git a/fuzz/fuzz_ike.c b/fuzz/fuzz_ike.c
index deb6074978..c8acc69b59 100644
--- a/fuzz/fuzz_ike.c
+++ b/fuzz/fuzz_ike.c
@@ -23,6 +23,8 @@ int LLVMFuzzerInitialize(int *argc, char ***argv)
dbg_default_set_level(-1);
library_init(NULL, "fuzz_ike");
libcharon_init();
+ atexit(library_deinit);
+ atexit(libcharon_deinit);
return 0;
}
diff --git a/fuzz/fuzz_radius.c b/fuzz/fuzz_radius.c
index bfaf81d78d..7cc18baf3d 100644
--- a/fuzz/fuzz_radius.c
+++ b/fuzz/fuzz_radius.c
@@ -26,6 +26,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv)
{
return 1;
}
+ atexit(library_deinit);
return 0;
}
diff --git a/fuzz/fuzz_tls.c b/fuzz/fuzz_tls.c
index 54279fbaca..ee72f70c81 100644
--- a/fuzz/fuzz_tls.c
+++ b/fuzz/fuzz_tls.c
@@ -95,6 +95,14 @@ static void setup_cert()
}
}
+/**
+ * Unload the test certificate/credential set
+ */
+static void teardown_cert()
+{
+ creds->destroy(creds);
+}
+
/**
* Minimal TLS application stub for fuzzing
*/
@@ -141,7 +149,9 @@ int LLVMFuzzerInitialize(int *argc, char ***argv)
{
return 1;
}
+ atexit(library_deinit);
setup_cert();
+ atexit(teardown_cert);
return 0;
}
diff --git a/fuzz/fuzz_vici.c b/fuzz/fuzz_vici.c
index b8a9b75d91..df8b46b65c 100644
--- a/fuzz/fuzz_vici.c
+++ b/fuzz/fuzz_vici.c
@@ -23,6 +23,8 @@ int LLVMFuzzerInitialize(int *argc, char ***argv)
dbg_default_set_level(-1);
library_init(NULL, "fuzz_vici");
libcharon_init();
+ atexit(library_deinit);
+ atexit(libcharon_deinit);
return 0;
}
diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c
index 60089684b8..3b3e6a418d 100644
--- a/src/libstrongswan/plugins/openssl/openssl_plugin.c
+++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c
@@ -722,9 +722,31 @@ METHOD(plugin_t, get_features, int,
return count;
}
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static int unload_ossl_provider(OSSL_PROVIDER *provider, void *cbdata)
+{
+ OSSL_PROVIDER_unload(provider);
+ return 1;
+}
+#endif
+
METHOD(plugin_t, destroy, void,
private_openssl_plugin_t *this)
{
+/* with OpenSSL 3 there is a problem with atexit() handlers registered by
+ * OpenSSL and some of our executables (e.g. swanctl or pki). because plugins
+ * are loaded after atexit() has been called to register library_deinit(), the
+ * handler registered by OpenSSL will run before ours. so when the latter
+ * destroys the plugins it's a bad idea to try to access any OpenSSL objects as
+ * they might already be invalid. so we generally don't unload the providers
+ * and just whitelist the leaks, however, that doesn't work for our fuzzers on
+ * OSS-Fuzz, so we detect this context here and unload the providers */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (strpfx(lib->ns, "fuzz_"))
+ {
+ OSSL_PROVIDER_do_all(NULL, unload_ossl_provider, NULL);
+ }
+#endif
/* OpenSSL 1.1.0 cleans up itself at exit and while OPENSSL_cleanup() exists we
* can't call it as we couldn't re-initialize the library (as required by the