summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Levitte <levitte@openssl.org>2021-03-01 13:27:24 +0100
committerRichard Levitte <levitte@openssl.org>2021-03-04 16:09:02 +0100
commitc2ec2bb7c146d1e48568f27d11dca02c06c36338 (patch)
tree22e81115abe5372b5be75a1ed9b825c821d14297
parentMake ossl_provider_disable_fallback_loading() thread safe (diff)
downloadopenssl-c2ec2bb7c146d1e48568f27d11dca02c06c36338.tar.xz
openssl-c2ec2bb7c146d1e48568f27d11dca02c06c36338.zip
Make provider provider_init thread safe, and flag checking/setting too
provider_init() makes changes in the provider structure, and needs a bit of protection to ensure that doesn't happen concurrently with race conditions. This also demands a bit of protection of the flags, since they are bits and presumably occupy the same byte in memory. Reviewed-by: Paul Dale <pauli@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/14354)
-rw-r--r--crypto/provider_core.c46
1 files changed, 35 insertions, 11 deletions
diff --git a/crypto/provider_core.c b/crypto/provider_core.c
index 3696ba1478..1326f83f7e 100644
--- a/crypto/provider_core.c
+++ b/crypto/provider_core.c
@@ -48,6 +48,9 @@ struct ossl_provider_st {
unsigned int flag_fallback:1; /* Can be used as fallback */
unsigned int flag_activated_as_fallback:1;
+ /* Getting and setting the flags require synchronization */
+ CRYPTO_RWLOCK *flag_lock;
+
/* OpenSSL library side data */
CRYPTO_REF_COUNT refcnt;
CRYPTO_RWLOCK *refcnt_lock; /* For the ref counter */
@@ -257,6 +260,7 @@ static OSSL_PROVIDER *provider_new(const char *name,
#endif
|| !ossl_provider_up_ref(prov) /* +1 One reference to be returned */
|| (prov->opbits_lock = CRYPTO_THREAD_lock_new()) == NULL
+ || (prov->flag_lock = CRYPTO_THREAD_lock_new()) == NULL
|| (prov->name = OPENSSL_strdup(name)) == NULL) {
ossl_provider_free(prov);
ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
@@ -377,6 +381,7 @@ void ossl_provider_free(OSSL_PROVIDER *prov)
OPENSSL_free(prov->path);
sk_INFOPAIR_pop_free(prov->parameters, free_infopair);
CRYPTO_THREAD_lock_free(prov->opbits_lock);
+ CRYPTO_THREAD_lock_free(prov->flag_lock);
#ifndef HAVE_ATOMICS
CRYPTO_THREAD_lock_free(prov->refcnt_lock);
CRYPTO_THREAD_lock_free(prov->activatecnt_lock);
@@ -472,9 +477,19 @@ static int provider_init(OSSL_PROVIDER *prov)
OSSL_FUNC_provider_get_reason_strings_fn *p_get_reason_strings = NULL;
# endif
#endif
+ int ok = 0;
- if (prov->flag_initialized)
- return 1;
+ /*
+ * The flag lock is used to lock init, not only because the flag is
+ * checked here and set at the end, but also because this function
+ * modifies a number of things in the provider structure that this
+ * function needs to perform under lock anyway.
+ */
+ CRYPTO_THREAD_write_lock(prov->flag_lock);
+ if (prov->flag_initialized) {
+ ok = 1;
+ goto end;
+ }
/*
* If the init function isn't set, it indicates that this provider is
@@ -482,7 +497,7 @@ static int provider_init(OSSL_PROVIDER *prov)
*/
if (prov->init_function == NULL) {
#ifdef FIPS_MODULE
- return 0;
+ goto end;
#else
if (prov->module == NULL) {
char *allocated_path = NULL;
@@ -493,13 +508,14 @@ static int provider_init(OSSL_PROVIDER *prov)
if ((prov->module = DSO_new()) == NULL) {
/* DSO_new() generates an error already */
- return 0;
+ goto end;
}
if ((store = get_provider_store(prov->libctx)) == NULL
|| !CRYPTO_THREAD_read_lock(store->lock))
- return 0;
+ goto end;
load_dir = store->default_path;
+ CRYPTO_THREAD_unlock(store->lock);
if (load_dir == NULL) {
load_dir = ossl_safe_getenv("OPENSSL_MODULES");
@@ -516,7 +532,6 @@ static int provider_init(OSSL_PROVIDER *prov)
DSO_convert_filename(prov->module, prov->name);
if (module_path != NULL)
merged_path = DSO_merge(prov->module, module_path, load_dir);
- CRYPTO_THREAD_unlock(store->lock);
if (merged_path == NULL
|| (DSO_load(prov->module, merged_path, NULL, 0)) == NULL) {
@@ -544,7 +559,7 @@ static int provider_init(OSSL_PROVIDER *prov)
DSO_free(prov->module);
prov->module = NULL;
#endif
- return 0;
+ goto end;
}
prov->provctx = tmp_provctx;
@@ -605,7 +620,7 @@ static int provider_init(OSSL_PROVIDER *prov)
cnt = 0;
while (reasonstrings[cnt].id != 0) {
if (ERR_GET_LIB(reasonstrings[cnt].id) != 0)
- return 0;
+ goto end;
cnt++;
}
cnt++; /* One for the terminating item */
@@ -614,7 +629,7 @@ static int provider_init(OSSL_PROVIDER *prov)
prov->error_strings =
OPENSSL_zalloc(sizeof(ERR_STRING_DATA) * (cnt + 1));
if (prov->error_strings == NULL)
- return 0;
+ goto end;
/*
* Set the "library" name.
@@ -637,7 +652,11 @@ static int provider_init(OSSL_PROVIDER *prov)
/* With this flag set, this provider has become fully "loaded". */
prov->flag_initialized = 1;
- return 1;
+ ok = 1;
+
+ end:
+ CRYPTO_THREAD_unlock(prov->flag_lock);
+ return ok;
}
static int provider_deactivate(OSSL_PROVIDER *prov)
@@ -650,8 +669,11 @@ static int provider_deactivate(OSSL_PROVIDER *prov)
if (CRYPTO_DOWN_REF(&prov->activatecnt, &ref, prov->activatecnt_lock) <= 0)
return 0;
- if (ref < 1)
+ if (ref < 1) {
+ CRYPTO_THREAD_write_lock(prov->flag_lock);
prov->flag_activated = 0;
+ CRYPTO_THREAD_unlock(prov->flag_lock);
+ }
/* We don't deinit here, that's done in ossl_provider_free() */
return 1;
@@ -665,7 +687,9 @@ static int provider_activate(OSSL_PROVIDER *prov)
return 0;
if (provider_init(prov)) {
+ CRYPTO_THREAD_write_lock(prov->flag_lock);
prov->flag_activated = 1;
+ CRYPTO_THREAD_unlock(prov->flag_lock);
return 1;
}