Fix an issue in provider_activate_fallbacks()

The above function was running while holding the store lock with a read
lock. Unfortunately it actually modifies the store, so a write lock is
required instead.

Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/13660)
This commit is contained in:
Matt Caswell 2021-01-11 17:02:01 +00:00
parent b457c8f514
commit 7dd2cb5693

View File

@ -729,34 +729,50 @@ static int provider_forall_loaded(struct provider_store_st *store,
*/
static void provider_activate_fallbacks(struct provider_store_st *store)
{
if (store->use_fallbacks) {
int num_provs = sk_OSSL_PROVIDER_num(store->providers);
int activated_fallback_count = 0;
int i;
int use_fallbacks;
int num_provs;
int activated_fallback_count = 0;
int i;
for (i = 0; i < num_provs; i++) {
OSSL_PROVIDER *prov = sk_OSSL_PROVIDER_value(store->providers, i);
CRYPTO_THREAD_read_lock(store->lock);
use_fallbacks = store->use_fallbacks;
CRYPTO_THREAD_unlock(store->lock);
if (!use_fallbacks)
return;
if (ossl_provider_up_ref(prov)) {
if (prov->flag_fallback) {
if (provider_activate(prov)) {
prov->flag_activated_as_fallback = 1;
activated_fallback_count++;
}
}
ossl_provider_free(prov);
}
}
/*
* We assume that all fallbacks have been added to the store before
* any fallback is activated.
* TODO: We may have to reconsider this, IF we find ourselves adding
* fallbacks after any previous fallback has been activated.
*/
if (activated_fallback_count > 0)
store->use_fallbacks = 0;
CRYPTO_THREAD_write_lock(store->lock);
/* Check again, just in case another thread changed it */
use_fallbacks = store->use_fallbacks;
if (!use_fallbacks) {
CRYPTO_THREAD_unlock(store->lock);
return;
}
num_provs = sk_OSSL_PROVIDER_num(store->providers);
for (i = 0; i < num_provs; i++) {
OSSL_PROVIDER *prov = sk_OSSL_PROVIDER_value(store->providers, i);
if (ossl_provider_up_ref(prov)) {
if (prov->flag_fallback) {
if (provider_activate(prov)) {
prov->flag_activated_as_fallback = 1;
activated_fallback_count++;
}
}
ossl_provider_free(prov);
}
}
/*
* We assume that all fallbacks have been added to the store before
* any fallback is activated.
* TODO: We may have to reconsider this, IF we find ourselves adding
* fallbacks after any previous fallback has been activated.
*/
if (activated_fallback_count > 0)
store->use_fallbacks = 0;
CRYPTO_THREAD_unlock(store->lock);
}
int ossl_provider_forall_loaded(OSSL_LIB_CTX *ctx,
@ -776,10 +792,9 @@ int ossl_provider_forall_loaded(OSSL_LIB_CTX *ctx,
#endif
if (store != NULL) {
CRYPTO_THREAD_read_lock(store->lock);
provider_activate_fallbacks(store);
CRYPTO_THREAD_read_lock(store->lock);
/*
* Now, we sweep through all providers
*/
@ -794,9 +809,7 @@ int ossl_provider_forall_loaded(OSSL_LIB_CTX *ctx,
int ossl_provider_available(OSSL_PROVIDER *prov)
{
if (prov != NULL) {
CRYPTO_THREAD_read_lock(prov->store->lock);
provider_activate_fallbacks(prov->store);
CRYPTO_THREAD_unlock(prov->store->lock);
return prov->flag_activated;
}