From: Neil Horman Date: Thu, 20 Nov 2025 16:49:19 +0000 (-0500) Subject: ensure destructor key is created prior to any other thread specific key X-Git-Tag: 3.6-PRE-CLANG-FORMAT-WEBKIT~24 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5bf627c977f7efb545494c6bd77e898d4a796c6f;p=thirdparty%2Fopenssl.git ensure destructor key is created prior to any other thread specific key https://github.com/openssl/openssl/issues/29077 found that, in the event that a pthread key is created prior to the destructor_key, glibc will NULL-ify any thread specific data before the init_thread_destructor runs, leading to leaks. Ensure that we always create the destructor key prior to any other thread local storage keys Fixes #29907 Reviewed-by: Dmitry Belyavskiy Reviewed-by: Norbert Pocs Reviewed-by: Nikola Pajkovsky (Merged from https://github.com/openssl/openssl/pull/29182) (cherry picked from commit 66f92cfb925e5c4c830ab65cf738ab49c5e553a4) --- diff --git a/crypto/initthread.c b/crypto/initthread.c index 07f0cc1c5fe..86130345e95 100644 --- a/crypto/initthread.c +++ b/crypto/initthread.c @@ -236,12 +236,27 @@ static void init_thread_destructor(void *hands) OPENSSL_free(hands); } -int ossl_init_thread(void) +static CRYPTO_ONCE ossl_init_thread_runonce = CRYPTO_ONCE_STATIC_INIT; +static CRYPTO_THREAD_ID recursion_guard = (CRYPTO_THREAD_ID)-1; + +DEFINE_RUN_ONCE_STATIC(ossl_init_thread_once) { + recursion_guard = CRYPTO_THREAD_get_current_id(); if (!CRYPTO_THREAD_init_local(&destructor_key.value, init_thread_destructor)) return 0; + recursion_guard = (CRYPTO_THREAD_ID)0; + return 1; +} + +int ossl_init_thread(void) +{ + if (CRYPTO_THREAD_compare_id(recursion_guard, + CRYPTO_THREAD_get_current_id())) + return 1; + if (!RUN_ONCE(&ossl_init_thread_runonce, ossl_init_thread_once)) + return 0; return 1; } diff --git a/crypto/threads_none.c b/crypto/threads_none.c index 04bc4f1d7d2..4e0d8634aa8 100644 --- a/crypto/threads_none.c +++ b/crypto/threads_none.c @@ -10,6 +10,7 @@ #include #include "internal/cryptlib.h" #include "internal/rcu.h" +#include "crypto/cryptlib.h" #include "rcu_internal.h" #if !defined(OPENSSL_THREADS) || defined(CRYPTO_TDEBUG) @@ -164,6 +165,11 @@ int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *)) { int entry_idx = 0; +# ifndef FIPS_MODULE + if (!ossl_init_thread()) + return 0; +# endif + for (entry_idx = 0; entry_idx < OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX; entry_idx++) { if (!thread_local_storage[entry_idx].used) break; diff --git a/crypto/threads_pthread.c b/crypto/threads_pthread.c index 9d9958e68fe..c516fc340a6 100644 --- a/crypto/threads_pthread.c +++ b/crypto/threads_pthread.c @@ -980,6 +980,12 @@ int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void)) int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *)) { + +# ifndef FIPS_MODULE + if (!ossl_init_thread()) + return 0; +# endif + if (pthread_key_create(key, cleanup) != 0) return 0; diff --git a/crypto/threads_win.c b/crypto/threads_win.c index 11029ea0c0b..a83b9e55704 100644 --- a/crypto/threads_win.c +++ b/crypto/threads_win.c @@ -556,6 +556,12 @@ int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void)) int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *)) { + +# ifndef FIPS_MODULE + if (!ossl_init_thread()) + return 0; +# endif + *key = TlsAlloc(); if (*key == TLS_OUT_OF_INDEXES) return 0;