Prevent recursive call of OPENSSL_INIT_LOAD_CONFIG
authorTomas Mraz <tomas@openssl.org>
Tue, 3 Aug 2021 15:29:04 +0000 (17:29 +0200)
committerPauli <pauli@openssl.org>
Wed, 4 Aug 2021 23:21:00 +0000 (09:21 +1000)
If objects are added in a config file the OPENSSL_INIT_LOAD_CONFIG
will be called recursively which results in hang in RUN_ONCE.

Fixes #16186

Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/16210)

crypto/init.c

index 552a4fa66c2d502820538e36cf6d14a26214c539..6a27d1a8e440318cdb9440cc4449c60fe8d42d04 100644 (file)
@@ -44,6 +44,7 @@ struct ossl_init_stop_st {
 
 static OPENSSL_INIT_STOP *stop_handlers = NULL;
 static CRYPTO_RWLOCK *init_lock = NULL;
+static CRYPTO_THREAD_LOCAL in_init_config_local;
 
 static CRYPTO_ONCE base = CRYPTO_ONCE_STATIC_INIT;
 static int base_inited = 0;
@@ -61,7 +62,10 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_base)
     OPENSSL_cpuid_setup();
 
     if (!ossl_init_thread())
-        return 0;
+        goto err;
+
+    if (!CRYPTO_THREAD_init_local(&in_init_config_local, NULL))
+        goto err;
 
     base_inited = 1;
     return 1;
@@ -366,6 +370,8 @@ void OPENSSL_cleanup(void)
     CRYPTO_THREAD_lock_free(init_lock);
     init_lock = NULL;
 
+    CRYPTO_THREAD_cleanup_local(&in_init_config_local);
+
     /*
      * We assume we are single-threaded for this function, i.e. no race
      * conditions for the various "*_inited" vars below.
@@ -566,22 +572,29 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
         return 0;
 
     if (opts & OPENSSL_INIT_LOAD_CONFIG) {
-        int ret;
+        int loading = CRYPTO_THREAD_get_local(&in_init_config_local) != NULL;
 
-        if (settings == NULL) {
-            ret = RUN_ONCE(&config, ossl_init_config);
-        } else {
-            if (!CRYPTO_THREAD_write_lock(init_lock))
+        /* If called recursively from OBJ_ calls, just skip it. */
+        if (!loading) {
+            int ret;
+
+            if (!CRYPTO_THREAD_set_local(&in_init_config_local, (void *)-1))
+                return 0;
+            if (settings == NULL) {
+                ret = RUN_ONCE(&config, ossl_init_config);
+            } else {
+                if (!CRYPTO_THREAD_write_lock(init_lock))
+                    return 0;
+                conf_settings = settings;
+                ret = RUN_ONCE_ALT(&config, ossl_init_config_settings,
+                                   ossl_init_config);
+                conf_settings = NULL;
+                CRYPTO_THREAD_unlock(init_lock);
+            }
+
+            if (ret <= 0)
                 return 0;
-            conf_settings = settings;
-            ret = RUN_ONCE_ALT(&config, ossl_init_config_settings,
-                               ossl_init_config);
-            conf_settings = NULL;
-            CRYPTO_THREAD_unlock(init_lock);
         }
-
-        if (ret <= 0)
-            return 0;
     }
 
     if ((opts & OPENSSL_INIT_ASYNC)