mirror of https://github.com/openssl/openssl.git
				
				
				
			core: modify ossl_provider_forall_loaded() to avoid locking for the callbacks
To avoid recursive lock issues, a copy is taken of the provider list and the callbacks are made without holding the store lock. Fixes #14251 Reviewed-by: Shane Lontis <shane.lontis@oracle.com> (Merged from https://github.com/openssl/openssl/pull/14489)
This commit is contained in:
		
							parent
							
								
									3d0b56785a
								
							
						
					
					
						commit
						7bbfbc8239
					
				|  | @ -726,36 +726,6 @@ void *ossl_provider_ctx(const OSSL_PROVIDER *prov) | |||
|     return prov->provctx; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static int provider_forall_loaded(struct provider_store_st *store, | ||||
|                                   int *found_activated, | ||||
|                                   int (*cb)(OSSL_PROVIDER *provider, | ||||
|                                             void *cbdata), | ||||
|                                   void *cbdata) | ||||
| { | ||||
|     int i; | ||||
|     int ret = 1; | ||||
|     int num_provs; | ||||
| 
 | ||||
|     num_provs = sk_OSSL_PROVIDER_num(store->providers); | ||||
| 
 | ||||
|     if (found_activated != NULL) | ||||
|         *found_activated = 0; | ||||
|     for (i = 0; i < num_provs; i++) { | ||||
|         OSSL_PROVIDER *prov = | ||||
|             sk_OSSL_PROVIDER_value(store->providers, i); | ||||
| 
 | ||||
|         if (prov->flag_activated) { | ||||
|             if (found_activated != NULL) | ||||
|                 *found_activated = 1; | ||||
|             if (!(ret = cb(prov, cbdata))) | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * This function only does something once when store->use_fallbacks == 1, | ||||
|  * and then sets store->use_fallbacks = 0, so the second call and so on is | ||||
|  | @ -814,8 +784,9 @@ int ossl_provider_forall_loaded(OSSL_LIB_CTX *ctx, | |||
|                                           void *cbdata), | ||||
|                                 void *cbdata) | ||||
| { | ||||
|     int ret = 1; | ||||
|     int ret = 0, i, j; | ||||
|     struct provider_store_st *store = get_provider_store(ctx); | ||||
|     STACK_OF(OSSL_PROVIDER) *provs = NULL; | ||||
| 
 | ||||
| #ifndef FIPS_MODULE | ||||
|     /*
 | ||||
|  | @ -825,18 +796,46 @@ int ossl_provider_forall_loaded(OSSL_LIB_CTX *ctx, | |||
|     OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); | ||||
| #endif | ||||
| 
 | ||||
|     if (store != NULL) { | ||||
|     if (store == NULL) | ||||
|         return 1; | ||||
|     provider_activate_fallbacks(store); | ||||
| 
 | ||||
|         CRYPTO_THREAD_read_lock(store->lock); | ||||
|     /*
 | ||||
|          * Now, we sweep through all providers | ||||
|      * Under lock, grab a copy of the provider list and up_ref each | ||||
|      * provider so that they don't disappear underneath us. | ||||
|      */ | ||||
|         ret = provider_forall_loaded(store, NULL, cb, cbdata); | ||||
| 
 | ||||
|     CRYPTO_THREAD_read_lock(store->lock); | ||||
|     provs = sk_OSSL_PROVIDER_dup(store->providers); | ||||
|     if (provs == NULL) { | ||||
|         CRYPTO_THREAD_unlock(store->lock); | ||||
|         return 0; | ||||
|     } | ||||
|     j = sk_OSSL_PROVIDER_num(provs); | ||||
|     for (i = 0; i < j; i++) | ||||
|         if (!ossl_provider_up_ref(sk_OSSL_PROVIDER_value(provs, i))) | ||||
|             goto err_unlock; | ||||
|     CRYPTO_THREAD_unlock(store->lock); | ||||
| 
 | ||||
|     /*
 | ||||
|      * Now, we sweep through all providers not under lock | ||||
|      */ | ||||
|     for (j = 0; j < i; j++) { | ||||
|         OSSL_PROVIDER *prov = sk_OSSL_PROVIDER_value(provs, j); | ||||
| 
 | ||||
|         if (prov->flag_activated && !cb(prov, cbdata)) | ||||
|             goto finish; | ||||
|     } | ||||
| 
 | ||||
|     ret = 1; | ||||
|     goto finish; | ||||
| 
 | ||||
|  err_unlock: | ||||
|     CRYPTO_THREAD_unlock(store->lock); | ||||
|  finish: | ||||
|     /* The pop_free call doesn't do what we want on an error condition */ | ||||
|     for (j = 0; j < i; j++) | ||||
|         ossl_provider_free(sk_OSSL_PROVIDER_value(provs, j)); | ||||
|     sk_OSSL_PROVIDER_free(provs); | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue