From 07f42f97b04e32ce7bee1c82cf23facdba48d980 Mon Sep 17 00:00:00 2001 From: Felipe Zipitria Date: Tue, 13 Oct 2026 09:25:53 -0300 Subject: [PATCH] fix: pair curl_global_init with curl_global_cleanup on reload modsecurity_init() calls curl_global_init(CURL_GLOBAL_ALL) on every (re)start and nothing ever called curl_global_cleanup(). Each graceful restart therefore initialised libcurl's TLS backend once more on top of the previous state. With a GnuTLS backed libcurl that leaks the random source set up per init, and after a few thousand reloads the process fails with GnuTLS errors until a full restart. curl_global_cleanup() is now registered as a cleanup of the configuration pool that was passed to modsecurity_init(), so each init is released when that configuration goes away. The early version that cleaned up per utilisation broke mod_ssl with OpenSSL before 1.1.0; tying it to the configuration pool keeps one init/cleanup pair per configuration generation, the same lifetime mod_ssl's own state has. Fixes #3590 Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_0181jBv5JdNQviwDzfnkf1Gy --- apache2/modsecurity.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 29ec5167c6..a1acf9d778 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -178,6 +178,13 @@ int msr_global_mutex_unlock(modsec_rec* msr, apr_global_mutex_t* lock, const cha return rc; } +#ifdef WITH_CURL +static apr_status_t modsecurity_curl_cleanup(void *data) { + curl_global_cleanup(); + return APR_SUCCESS; +} +#endif + /** * Initialise the modsecurity engine. This function must be invoked * after configuration processing is complete as Apache needs to know the @@ -192,14 +199,20 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { #endif /** - * Notice that curl is initialized here but never cleaned up. First version - * of this implementation curl was initialized and cleaned for every - * utilization. Turns out that it was not only cleaning stuff that was - * utilized by Curl but also other OpenSSL stuff that was utilized by - * mod_ssl leading the SSL support to crash. + * curl_global_init() runs on every (re)start, so it has to be paired + * with curl_global_cleanup() when the configuration pool goes away, + * otherwise the TLS backend is initialised once more on each reload + * without ever being released. With a GnuTLS backed libcurl that + * exhausts the random source after a few thousand reloads (#3590). + * + * The cleanup is registered on the configuration pool, not called per + * utilisation as an early version did: with OpenSSL before 1.1.0 that + * tore down global OpenSSL state that mod_ssl was still using. */ #ifdef WITH_CURL curl_global_init(CURL_GLOBAL_ALL); + apr_pool_cleanup_register(mp, NULL, modsecurity_curl_cleanup, + apr_pool_cleanup_null); #endif /* Serial audit log mutex */ rc = acquire_global_lock(&msce->auditlog_lock, mp);