Add RAND_set_urandom_fd.

Chromium uses a zygote process and a sandbox on Linux. In order for RAND_bytes
to be functional and guaranteed fork-safe inside the renderers, /dev/urandom
must be prewarmed. Calling RAND_bytes initializes a thread-local ChaCha20 key
when rdrand is available. So that key is fork-safe and to avoid tempting any
dragons by touching pthreads APIs before a non-exec fork, add a
RAND_set_urandom_fd API. It allows the consumer to supply the /dev/urandom fd
and promises to be fork-safe, both in initializing key material and use of
pthreads.

This doesn't affect any current shipping versions of Chrome.

BUG=462040

Change-Id: I1037e21e525918971380e4ea1371703c8237a0b0
Reviewed-on: https://boringssl-review.googlesource.com/5302
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/rand/urandom.c b/crypto/rand/urandom.c
index 788a979..397ded9 100644
--- a/crypto/rand/urandom.c
+++ b/crypto/rand/urandom.c
@@ -118,6 +118,19 @@
   CRYPTO_STATIC_MUTEX_unlock(&global_lock);
 }
 
+void RAND_set_urandom_fd(int fd) {
+  CRYPTO_STATIC_MUTEX_lock_write(&global_lock);
+  if (urandom_fd != -2) {
+    /* |RAND_set_urandom_fd| may not be called after the RNG is used. */
+    abort();
+  }
+  urandom_fd = dup(fd);
+  if (urandom_fd < 0) {
+    abort();
+  }
+  CRYPTO_STATIC_MUTEX_unlock(&global_lock);
+}
+
 /* read_full reads exactly |len| bytes from |fd| into |out| and returns 1. In
  * the case of an error it returns 0. */
 static char read_full(int fd, uint8_t *out, size_t len) {
diff --git a/include/openssl/rand.h b/include/openssl/rand.h
index a43505a..2918c7e 100644
--- a/include/openssl/rand.h
+++ b/include/openssl/rand.h
@@ -33,6 +33,21 @@
 OPENSSL_EXPORT void RAND_cleanup(void);
 
 
+/* Obscure functions. */
+
+#if !defined(OPENSSL_WINDOWS)
+/* RAND_set_urandom_fd causes the module to use a copy of |fd| for system
+ * randomness rather opening /dev/urandom internally. The caller retains
+ * ownership of |fd| and is at liberty to close it at any time. This is useful
+ * if, due to a sandbox, /dev/urandom isn't available. If used, it must be
+ * called before |RAND_bytes| is called in the current address space.
+ *
+ * |RAND_set_urandom_fd| does not buffer any entropy, so it is safe to call
+ * |fork| between |RAND_set_urandom_fd| and the first call to |RAND_bytes|. */
+OPENSSL_EXPORT void RAND_set_urandom_fd(int fd);
+#endif
+
+
 /* Deprecated functions */
 
 /* RAND_pseudo_bytes is a wrapper around |RAND_bytes|. */