Commit 7122f81416 for openssl.org
commit 7122f8141674140654a1b8a9cc7cd790b9fbb9dd
Author: Pavol Žáčik <zacik.pa@gmail.com>
Date: Wed Sep 2 14:54:28 2026 +0200
Do not advertise OPENSSL_INIT_LOAD_CONFIG in optsdone too soon
If there was no explicit call to OPENSSL_init_crypto before starting
threading, it would result in a race between loading the config in
one thread, and attempting to use features dependent on the config,
e.g., providers in other threads.
The first thread that gets into OPENSSL_init_crypto would start loading
the config and set `loading` to 1 The same thread may re-enter the function
recursively and should do nothing, but it would actually update `optsdone`
with OPENSSL_INIT_LOAD_CONFIG, even though the loading has not finished yet.
This commit fixes the issue by masking the opts bit out if we re-enter
OPENSSL_init_crypto.
Assisted-by: Claude:claude-opus-4.8
Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
MergeDate: Fri Sep 4 07:15:24 2026
(Merged from https://github.com/openssl/openssl/pull/32646)
diff --git a/crypto/init.c b/crypto/init.c
index 302e37f7fa..1863894b39 100644
--- a/crypto/init.c
+++ b/crypto/init.c
@@ -348,6 +348,7 @@ void ossl_cleanup_destructor(void)
int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
{
uint64_t tmp;
+ uint64_t optsdone_bits = opts;
int aloaddone = 0;
/* Applications depend on 0 being returned when cleanup was already done */
@@ -453,8 +454,15 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
if (opts & OPENSSL_INIT_LOAD_CONFIG) {
int loading = CRYPTO_THREAD_get_local(&in_init_config_local) != NULL;
- /* If called recursively from OBJ_ calls, just skip it. */
- if (!loading) {
+ /* If called recursively from OBJ_ calls during config loading,
+ * we have to mask OPENSSL_INIT_LOAD_CONFIG in optsdone to not
+ * advertise that config loading is complete, otherwise other
+ * threads may proceed, e.g., to fetching from a provider that
+ * is not yet loaded.
+ */
+ if (loading) {
+ optsdone_bits &= ~(uint64_t)OPENSSL_INIT_LOAD_CONFIG;
+ } else {
int ret;
if (!CRYPTO_THREAD_set_local(&in_init_config_local, (void *)-1))
@@ -480,7 +488,7 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
&& !RUN_ONCE(&async, ossl_init_async))
return 0;
- if (!CRYPTO_atomic_or(&optsdone, opts, &tmp, optsdone_lock))
+ if (!CRYPTO_atomic_or(&optsdone, optsdone_bits, &tmp, optsdone_lock))
return 0;
return 1;