From 5e393fedef3f0b9daa886a56b2713451d08f35b5 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Sat, 9 Jul 2016 13:02:18 +0100 Subject: [PATCH] Test getrandom(2) on Linux if available This patch changes the urandom PRNG to read one byte from the getrandom(2) Linux syscall on initialization in order to find any unexpected behavior. Change-Id: I8ef676854dc361e4f77527b53d1a14fd14d449a8 Reviewed-on: https://boringssl-review.googlesource.com/8681 Reviewed-by: Adam Langley Commit-Queue: Adam Langley CQ-Verified: CQ bot account: commit-bot@chromium.org --- crypto/rand/urandom.c | 63 +++++++++++++++++++++++++++++++++++++----- include/openssl/base.h | 4 +++ 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/crypto/rand/urandom.c b/crypto/rand/urandom.c index 4c8a5f71..b1ab13e0 100644 --- a/crypto/rand/urandom.c +++ b/crypto/rand/urandom.c @@ -12,6 +12,8 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define _GNU_SOURCE /* needed for syscall() on Linux. */ + #include #if !defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_UNSAFE_FUZZER_MODE) @@ -22,6 +24,10 @@ #include #include +#if defined(OPENSSL_LINUX) +#include +#endif + #include #include @@ -29,6 +35,43 @@ #include "../internal.h" +#if defined(OPENSSL_LINUX) + +#if defined(OPENSSL_X86_64) +#define EXPECTED_SYS_getrandom 318 +#elif defined(OPENSSL_X86) +#define EXPECTED_SYS_getrandom 355 +#elif defined(OPENSSL_AARCH64) +#define EXPECTED_SYS_getrandom 278 +#elif defined(OPENSSL_ARM) +#define EXPECTED_SYS_getrandom 384 +#elif defined(OPENSSL_PPC64LE) +#define EXPECTED_SYS_getrandom 359 +#endif + +#if defined(EXPECTED_SYS_getrandom) +#define USE_SYS_getrandom + +#if defined(SYS_getrandom) + +#if SYS_getrandom != EXPECTED_SYS_getrandom +#error "system call number for getrandom is not the expected value" +#endif + +#else /* SYS_getrandom */ + +#define SYS_getrandom EXPECTED_SYS_getrandom + +#endif /* SYS_getrandom */ + +#endif /* EXPECTED_SYS_getrandom */ + +#if !defined(GRND_NONBLOCK) +#define GRND_NONBLOCK 1 +#endif + +#endif /* OPENSSL_LINUX */ + /* This file implements a PRNG by reading from /dev/urandom, optionally with a * buffer, which is unsafe across |fork|. */ @@ -71,6 +114,12 @@ static void init_once(void) { int fd = urandom_fd_requested; 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 + if (fd == -2) { do { fd = open("/dev/urandom", O_RDONLY); @@ -144,7 +193,7 @@ static struct rand_buffer *get_thread_local_buffer(void) { if (buf == NULL) { return NULL; } - buf->used = BUF_SIZE; /* To trigger a |read_full| on first use. */ + buf->used = BUF_SIZE; /* To trigger a |fill_with_entropy| on first use. */ if (!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_URANDOM_BUF, buf, OPENSSL_free)) { OPENSSL_free(buf); @@ -154,14 +203,14 @@ static struct rand_buffer *get_thread_local_buffer(void) { return buf; } -/* 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) { +/* fill_with_entropy writes |len| bytes of entropy into |out|. It returns one + * on success and zero on error. */ +static char fill_with_entropy(uint8_t *out, size_t len) { ssize_t r; while (len > 0) { do { - r = read(fd, out, len); + r = read(urandom_fd, out, len); } while (r == -1 && errno == EINTR); if (r <= 0) { @@ -186,7 +235,7 @@ static void read_from_buffer(struct rand_buffer *buf, out += remaining; requested -= remaining; - if (!read_full(urandom_fd, buf->rand, BUF_SIZE)) { + if (!fill_with_entropy(buf->rand, BUF_SIZE)) { abort(); return; } @@ -213,7 +262,7 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) { } } - if (!read_full(urandom_fd, out, requested)) { + if (!fill_with_entropy(out, requested)) { abort(); } } diff --git a/include/openssl/base.h b/include/openssl/base.h index cb847d52..71f283d2 100644 --- a/include/openssl/base.h +++ b/include/openssl/base.h @@ -114,6 +114,10 @@ extern "C" { #define OPENSSL_WINDOWS #endif +#if defined(__linux__) +#define OPENSSL_LINUX +#endif + #if defined(TRUSTY) #define OPENSSL_TRUSTY #define OPENSSL_NO_THREADS