Commit 380aafd865 for openssl.org
commit 380aafd8651cf478744a5cfbe8ebf42e51396227
Author: Simo Sorce <simo@redhat.com>
Date: Mon Dec 8 14:06:17 2025 -0500
Move deferred self-test lock to FIPS_GLOBAL
The lock for the deferred FIPS self-tests was previously a static
global variable, initialized with CRYPTO_ONCE. This is problematic
when multiple library contexts are used in a single application.
This change moves the lock into the FIPS_GLOBAL structure, making it
per-library-context. The lock is now initialized when the FIPS
provider is initialized and freed when its context is torn down.
This improves encapsulation and avoids global state.
Signed-off-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/29222)
diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c
index 3808eb5ad5..b759bd9249 100644
--- a/providers/fips/fipsprov.c
+++ b/providers/fips/fipsprov.c
@@ -103,6 +103,9 @@ typedef struct fips_global_st {
#include "fips_indicator_params.inc"
#undef OSSL_FIPS_PARAM
+ /* Guards access to deferred self-test */
+ CRYPTO_RWLOCK *deferred_lock;
+
} FIPS_GLOBAL;
static void init_fips_option(FIPS_OPTION *opt, int enabled)
@@ -128,6 +131,8 @@ void *ossl_fips_prov_ossl_ctx_new(OSSL_LIB_CTX *libctx)
void ossl_fips_prov_ossl_ctx_free(void *fgbl)
{
+ if (((FIPS_GLOBAL *)fgbl)->deferred_lock)
+ CRYPTO_THREAD_lock_free(((FIPS_GLOBAL *)fgbl)->deferred_lock);
OPENSSL_free(fgbl);
}
@@ -808,12 +813,9 @@ static const OSSL_ALGORITHM *fips_query_internal(void *provctx, int operation_id
return fips_query(provctx, operation_id, no_cache);
}
-static void deferred_deinit(void);
-
static void fips_teardown(void *provctx)
{
/* Also free deferred variables when the FIPS Global context is killed */
- deferred_deinit();
OSSL_LIB_CTX_free(PROV_LIBCTX_OF(provctx));
ossl_prov_ctx_free(provctx);
}
@@ -1059,6 +1061,12 @@ int OSSL_provider_init_int(const OSSL_CORE_HANDLE *handle,
ossl_prov_cache_exported_algorithms(fips_ciphers, exported_fips_ciphers);
+ /* initialize deferred self-test infrastructure */
+ if ((fgbl->deferred_lock = CRYPTO_THREAD_lock_new()) == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_CREATE_LOCK);
+ goto err;
+ }
+
if (!SELF_TEST_post(&fgbl->selftest_params, 0)) {
ERR_raise(ERR_LIB_PROV, PROV_R_SELF_TEST_POST_FAILURE);
goto err;
@@ -1296,25 +1304,6 @@ void OSSL_INDICATOR_get_callback(OSSL_LIB_CTX *libctx,
}
}
-/* Deferred test infrastructure */
-
-/* Guards access to deferred self-test */
-static CRYPTO_RWLOCK *deferred_lock;
-
-static CRYPTO_ONCE deferred_once = CRYPTO_ONCE_STATIC_INIT;
-static void deferred_init(void)
-{
- if ((deferred_lock = CRYPTO_THREAD_lock_new()) == NULL)
- ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_CREATE_LOCK);
-}
-static void deferred_deinit(void)
-{
- if (deferred_lock) {
- CRYPTO_THREAD_lock_free(deferred_lock);
- deferred_lock = NULL;
- }
-}
-
static int FIPS_kat_deferred_execute(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx,
self_test_id_t id)
{
@@ -1354,14 +1343,15 @@ static int FIPS_kat_deferred_execute(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx,
static int FIPS_kat_deferred(OSSL_LIB_CTX *libctx, self_test_id_t id)
{
+ FIPS_GLOBAL *fgbl = ossl_lib_ctx_get_data(libctx,
+ OSSL_LIB_CTX_FIPS_PROV_INDEX);
int *rt = NULL;
int ret = 0;
- if (!CRYPTO_THREAD_run_once(&deferred_once, deferred_init))
- return 0;
-
- if (deferred_lock == NULL)
+ if (fgbl == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_STATE);
return 0;
+ }
/*
* before we do anything, make sure a local test is not already in
@@ -1383,7 +1373,7 @@ static int FIPS_kat_deferred(OSSL_LIB_CTX *libctx, self_test_id_t id)
return 1;
}
- if (CRYPTO_THREAD_write_lock(deferred_lock)) {
+ if (CRYPTO_THREAD_write_lock(fgbl->deferred_lock)) {
OSSL_SELF_TEST *st = NULL;
bool unset_key = false;
OSSL_CALLBACK *cb = NULL;
@@ -1440,7 +1430,7 @@ static int FIPS_kat_deferred(OSSL_LIB_CTX *libctx, self_test_id_t id)
CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_FIPS_DEFERRED_KEY,
libctx, NULL);
OPENSSL_free(rt);
- CRYPTO_THREAD_unlock(deferred_lock);
+ CRYPTO_THREAD_unlock(fgbl->deferred_lock);
}
return ret;
}