aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/rand
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2021-01-26 15:14:02 +0000
committerMatt Caswell <matt@openssl.org>2021-02-02 12:21:21 +0000
commitcd4e6a351201270cd2769e1e2af7e9fb875a3f80 (patch)
tree73694ef897b94508dd072a1f2a057940c9c502ed /crypto/rand
parenta0134d293e907672e2717fe54ce6a4b3ae425388 (diff)
downloadopenssl-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.c64
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;
}
/*