Split the FIPS mode PRNG lock in two. In FIPS mode, we maintain a lock in order to implement clearing DRBG state on process shutdown. This lock serves two purposes: 1. It protects the linked list of all DRBG states, which needs to be updated the first time a thread touches RAND_bytes, when a thread exits, and on process exit. 2. It ensures threads alive during process shutdown do not accidentally touch DRBGs after they are cleared, by way of taking a ton of read locks in RAND_bytes across some potentially time-consuming points. This means that when one of the rare events in (1) happens, it must contend with the flurry of read locks in (2). Split these uses into two locks. The second lock now only ever sees read locks until process shutdown, and the first lock is only accessed in rare cases. Change-Id: Ib856c7a3bb937bbfa5d08534031dbf4ed3315cab Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/45844 Commit-Queue: David Benjamin <davidben@google.com> Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/fipsmodule/rand/rand.c b/crypto/fipsmodule/rand/rand.c index aa0f05b..824efc8 100644 --- a/crypto/fipsmodule/rand/rand.c +++ b/crypto/fipsmodule/rand/rand.c
@@ -83,16 +83,18 @@ // called when the whole process is exiting. DEFINE_BSS_GET(struct rand_thread_state *, thread_states_list); DEFINE_STATIC_MUTEX(thread_states_list_lock); +DEFINE_STATIC_MUTEX(state_clear_all_lock); static void rand_thread_state_clear_all(void) __attribute__((destructor)); static void rand_thread_state_clear_all(void) { CRYPTO_STATIC_MUTEX_lock_write(thread_states_list_lock_bss_get()); + CRYPTO_STATIC_MUTEX_lock_write(state_clear_all_lock_bss_get()); for (struct rand_thread_state *cur = *thread_states_list_bss_get(); cur != NULL; cur = cur->next) { CTR_DRBG_clear(&cur->drbg); } - // |thread_states_list_lock is deliberately left locked so that any threads - // that are still running will hang if they try to call |RAND_bytes|. + // The locks are deliberately left locked so that any threads that are still + // running will hang if they try to call |RAND_bytes|. } #endif @@ -415,7 +417,7 @@ // bug on ppc64le. glibc may implement pthread locks by wrapping user code // in a hardware transaction, but, on some older versions of glibc and the // kernel, syscalls made with |syscall| did not abort the transaction. - CRYPTO_STATIC_MUTEX_lock_read(thread_states_list_lock_bss_get()); + CRYPTO_STATIC_MUTEX_lock_read(state_clear_all_lock_bss_get()); #endif if (!CTR_DRBG_reseed(&state->drbg, seed, NULL, 0)) { abort(); @@ -424,7 +426,7 @@ state->fork_generation = fork_generation; } else { #if defined(BORINGSSL_FIPS) - CRYPTO_STATIC_MUTEX_lock_read(thread_states_list_lock_bss_get()); + CRYPTO_STATIC_MUTEX_lock_read(state_clear_all_lock_bss_get()); #endif } @@ -453,7 +455,7 @@ } #if defined(BORINGSSL_FIPS) - CRYPTO_STATIC_MUTEX_unlock_read(thread_states_list_lock_bss_get()); + CRYPTO_STATIC_MUTEX_unlock_read(state_clear_all_lock_bss_get()); #endif }