From 7b668a873eca79116a429e3f3e4dc51107b968a3 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Tue, 22 Nov 2016 15:57:27 -0800 Subject: [PATCH] Enable getrandom for entropy gathering. This change will cause getrandom to be used in preference to /dev/urandom when supported by the kernel. This will also cause BoringSSL-using processes to block until the entropy pool is initialised on systems that support getrandom(2). Change-Id: I2d3a17891502c85884c77138ef0f3a719d7ecfe6 Reviewed-on: https://boringssl-review.googlesource.com/12421 Reviewed-by: Adam Langley Commit-Queue: Adam Langley CQ-Verified: CQ bot account: commit-bot@chromium.org --- crypto/rand/urandom.c | 70 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/crypto/rand/urandom.c b/crypto/rand/urandom.c index 25726259..17d194c5 100644 --- a/crypto/rand/urandom.c +++ b/crypto/rand/urandom.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -87,12 +88,16 @@ struct rand_buffer { /* requested_lock is used to protect the |*_requested| variables. */ static struct CRYPTO_STATIC_MUTEX requested_lock = CRYPTO_STATIC_MUTEX_INIT; -/* urandom_fd_requested is set by |RAND_set_urandom_fd|. It's protected by +/* The following constants are magic values of |urandom_fd|. */ +static const int kUnset = -2; +static const int kHaveGetrandom = -3; + +/* urandom_fd_requested is set by |RAND_set_urandom_fd|. It's protected by * |requested_lock|. */ -static int urandom_fd_requested = -2; +static int urandom_fd_requested = -2 /* kUnset */; /* urandom_fd is a file descriptor to /dev/urandom. It's protected by |once|. */ -static int urandom_fd = -2; +static int urandom_fd = -2 /* kUnset */; /* urandom_buffering_requested is set by |RAND_enable_fork_unsafe_buffering|. * It's protected by |requested_lock|. */ @@ -115,12 +120,31 @@ static void init_once(void) { CRYPTO_STATIC_MUTEX_unlock_read(&requested_lock); #if defined(USE_SYS_getrandom) - /* Initial test of getrandom to find any unexpected behavior. */ uint8_t dummy; - syscall(SYS_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK); -#endif + long getrandom_ret = + syscall(SYS_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK); - if (fd == -2) { + if (getrandom_ret == 1) { + urandom_fd = kHaveGetrandom; + return; + } else if (getrandom_ret == -1 && errno == EAGAIN) { + fprintf(stderr, + "getrandom indicates that the entropy pool has not been " + "initialized. Rather than continue with poor entropy, this process " + "will block until entropy is available.\n"); + do { + getrandom_ret = + syscall(SYS_getrandom, &dummy, sizeof(dummy), 0 /* no flags */); + } while (getrandom_ret == -1 && errno == EINTR); + + if (getrandom_ret == 1) { + urandom_fd = kHaveGetrandom; + return; + } + } +#endif /* USE_SYS_getrandom */ + + if (fd == kUnset) { do { fd = open("/dev/urandom", O_RDONLY); } while (fd == -1 && errno == EINTR); @@ -156,7 +180,9 @@ void RAND_set_urandom_fd(int fd) { CRYPTO_STATIC_MUTEX_unlock_write(&requested_lock); CRYPTO_once(&once, init_once); - if (urandom_fd != fd) { + if (urandom_fd == kHaveGetrandom) { + close(fd); + } else if (urandom_fd != fd) { abort(); // Already initialized. } } @@ -168,7 +194,7 @@ void RAND_enable_fork_unsafe_buffering(int fd) { abort(); } } else { - fd = -2; + fd = kUnset; } CRYPTO_STATIC_MUTEX_lock_write(&requested_lock); @@ -177,7 +203,15 @@ void RAND_enable_fork_unsafe_buffering(int fd) { CRYPTO_STATIC_MUTEX_unlock_write(&requested_lock); CRYPTO_once(&once, init_once); - if (urandom_buffering != 1 || (fd >= 0 && urandom_fd != fd)) { + if (urandom_buffering != 1) { + abort(); // Already initialized + } + + if (urandom_fd == kHaveGetrandom) { + if (fd >= 0) { + close(fd); + } + } else if (urandom_fd != fd) { abort(); // Already initialized. } } @@ -209,9 +243,19 @@ static char fill_with_entropy(uint8_t *out, size_t len) { ssize_t r; while (len > 0) { - do { - r = read(urandom_fd, out, len); - } while (r == -1 && errno == EINTR); + if (urandom_fd == kHaveGetrandom) { +#if defined(USE_SYS_getrandom) + do { + r = syscall(SYS_getrandom, out, len, 0 /* no flags */); + } while (r == -1 && errno == EINTR); +#else + abort(); +#endif + } else { + do { + r = read(urandom_fd, out, len); + } while (r == -1 && errno == EINTR); + } if (r <= 0) { return 0;