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
 }