]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
ensure destructor key is created prior to any other thread specific key
authorNeil Horman <nhorman@openssl.org>
Thu, 20 Nov 2025 16:49:19 +0000 (11:49 -0500)
committerNeil Horman <nhorman@openssl.org>
Mon, 1 Dec 2025 18:21:55 +0000 (13:21 -0500)
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 <beldmit@gmail.com>
Reviewed-by: Norbert Pocs <norbertp@openssl.org>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/29182)

crypto/initthread.c
crypto/threads_none.c
crypto/threads_pthread.c
crypto/threads_win.c

index 27b460009e1dcb0aaca3d3f65d71e9d37719e643..1be9ea977106bd145295bbebd6d801a2a4955803 100644 (file)
@@ -199,12 +199,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;
 }
 
index ac61f384501f2bf675dc1db4ba3fbbe7aa8e8c26..07029908f77f96de5b190607d038ce59265b0d40 100644 (file)
@@ -10,6 +10,7 @@
 #include <openssl/crypto.h>
 #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;
index ace2dc4990611a8eca6d187c361a7ecbd4fcd9c6..051c9ff411dac5ac19a465c838b7cb433d3477a7 100644 (file)
@@ -697,6 +697,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;
 
index 97b6d3eb73989d69a197226d28e67680568826e1..af92dfa0b2134ff0a2362447bdfe9b88558e5611 100644 (file)
@@ -548,6 +548,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;