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|. */