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 <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
This commit is contained in:
Adam Langley 2016-11-22 15:57:27 -08:00 committed by CQ bot account: commit-bot@chromium.org
parent c3c8882918
commit 7b668a873e

View File

@ -21,6 +21,7 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@ -87,12 +88,16 @@ struct rand_buffer {
/* requested_lock is used to protect the |*_requested| variables. */ /* requested_lock is used to protect the |*_requested| variables. */
static struct CRYPTO_STATIC_MUTEX requested_lock = CRYPTO_STATIC_MUTEX_INIT; static struct CRYPTO_STATIC_MUTEX requested_lock = CRYPTO_STATIC_MUTEX_INIT;
/* 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 /* urandom_fd_requested is set by |RAND_set_urandom_fd|. It's protected by
* |requested_lock|. */ * |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|. */ /* 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|. /* urandom_buffering_requested is set by |RAND_enable_fork_unsafe_buffering|.
* It's protected by |requested_lock|. */ * It's protected by |requested_lock|. */
@ -115,12 +120,31 @@ static void init_once(void) {
CRYPTO_STATIC_MUTEX_unlock_read(&requested_lock); CRYPTO_STATIC_MUTEX_unlock_read(&requested_lock);
#if defined(USE_SYS_getrandom) #if defined(USE_SYS_getrandom)
/* Initial test of getrandom to find any unexpected behavior. */
uint8_t dummy; uint8_t dummy;
long getrandom_ret =
syscall(SYS_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK); syscall(SYS_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK);
#endif
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 { do {
fd = open("/dev/urandom", O_RDONLY); fd = open("/dev/urandom", O_RDONLY);
} while (fd == -1 && errno == EINTR); } while (fd == -1 && errno == EINTR);
@ -156,7 +180,9 @@ void RAND_set_urandom_fd(int fd) {
CRYPTO_STATIC_MUTEX_unlock_write(&requested_lock); CRYPTO_STATIC_MUTEX_unlock_write(&requested_lock);
CRYPTO_once(&once, init_once); CRYPTO_once(&once, init_once);
if (urandom_fd != fd) { if (urandom_fd == kHaveGetrandom) {
close(fd);
} else if (urandom_fd != fd) {
abort(); // Already initialized. abort(); // Already initialized.
} }
} }
@ -168,7 +194,7 @@ void RAND_enable_fork_unsafe_buffering(int fd) {
abort(); abort();
} }
} else { } else {
fd = -2; fd = kUnset;
} }
CRYPTO_STATIC_MUTEX_lock_write(&requested_lock); 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_STATIC_MUTEX_unlock_write(&requested_lock);
CRYPTO_once(&once, init_once); 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. abort(); // Already initialized.
} }
} }
@ -209,9 +243,19 @@ static char fill_with_entropy(uint8_t *out, size_t len) {
ssize_t r; ssize_t r;
while (len > 0) { while (len > 0) {
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 { do {
r = read(urandom_fd, out, len); r = read(urandom_fd, out, len);
} while (r == -1 && errno == EINTR); } while (r == -1 && errno == EINTR);
}
if (r <= 0) { if (r <= 0) {
return 0; return 0;