diff options
author | Matt Caswell <matt@openssl.org> | 2021-01-26 15:14:02 +0000 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2021-02-02 12:21:21 +0000 |
commit | cd4e6a351201270cd2769e1e2af7e9fb875a3f80 (patch) | |
tree | 73694ef897b94508dd072a1f2a057940c9c502ed /crypto/rand | |
parent | a0134d293e907672e2717fe54ce6a4b3ae425388 (diff) | |
download | openssl-cd4e6a351201270cd2769e1e2af7e9fb875a3f80.tar.gz |
Refactor RAND_get0_primary() locking
Make sure we never read or write to dgbl->primary outside of a lock.
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/13987)
Diffstat (limited to 'crypto/rand')
-rw-r--r-- | crypto/rand/rand_lib.c | 64 |
1 files changed, 39 insertions, 25 deletions
diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c index 4e561568cd..69afa9d2ea 100644 --- a/crypto/rand/rand_lib.c +++ b/crypto/rand/rand_lib.c @@ -553,38 +553,52 @@ static EVP_RAND_CTX *rand_new_drbg(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent, EVP_RAND_CTX *RAND_get0_primary(OSSL_LIB_CTX *ctx) { RAND_GLOBAL *dgbl = rand_get_global(ctx); + EVP_RAND_CTX *ret; if (dgbl == NULL) return NULL; - if (dgbl->primary == NULL) { - if (!CRYPTO_THREAD_write_lock(dgbl->lock)) - return NULL; + if (!CRYPTO_THREAD_read_lock(dgbl->lock)) + return NULL; + + ret = dgbl->primary; + CRYPTO_THREAD_unlock(dgbl->lock); + + if (ret != NULL) + return ret; + + if (!CRYPTO_THREAD_write_lock(dgbl->lock)) + return NULL; + + ret = dgbl->primary; + if (ret != NULL) { + CRYPTO_THREAD_unlock(dgbl->lock); + return ret; + } + #ifndef FIPS_MODULE - if (dgbl->seed == NULL) { - ERR_set_mark(); - dgbl->seed = rand_new_seed(ctx); - ERR_pop_to_mark(); - } + if (dgbl->seed == NULL) { + ERR_set_mark(); + dgbl->seed = rand_new_seed(ctx); + ERR_pop_to_mark(); + } #endif - if (dgbl->primary == NULL) - dgbl->primary = rand_new_drbg(ctx, dgbl->seed, - PRIMARY_RESEED_INTERVAL, - PRIMARY_RESEED_TIME_INTERVAL); - /* - * The primary DRBG may be shared between multiple threads so we must - * enable locking. - */ - if (dgbl->primary != NULL && !EVP_RAND_enable_locking(dgbl->primary)) { - ERR_raise(ERR_LIB_EVP, EVP_R_UNABLE_TO_ENABLE_LOCKING); - EVP_RAND_CTX_free(dgbl->primary); - dgbl->primary = NULL; - CRYPTO_THREAD_lock_free(dgbl->lock); - return NULL; - } - CRYPTO_THREAD_unlock(dgbl->lock); + + ret = dgbl->primary = rand_new_drbg(ctx, dgbl->seed, + PRIMARY_RESEED_INTERVAL, + PRIMARY_RESEED_TIME_INTERVAL); + /* + * The primary DRBG may be shared between multiple threads so we must + * enable locking. + */ + if (ret != NULL && !EVP_RAND_enable_locking(ret)) { + ERR_raise(ERR_LIB_EVP, EVP_R_UNABLE_TO_ENABLE_LOCKING); + EVP_RAND_CTX_free(ret); + ret = dgbl->primary = NULL; } - return dgbl->primary; + CRYPTO_THREAD_unlock(dgbl->lock); + + return ret; } /* |