Skip to content

Commit

Permalink
Test getrandom(2) on Linux if available
Browse files Browse the repository at this point in the history
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 <alangley@gmail.com>
Commit-Queue: Adam Langley <alangley@gmail.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
  • Loading branch information
ghedo authored and CQ bot account: commit-bot@chromium.org committed Oct 27, 2016
1 parent 9ef99d5 commit 5e393fe
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 7 deletions.
63 changes: 56 additions & 7 deletions crypto/rand/urandom.c
Expand Up @@ -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 <openssl/rand.h>

#if !defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_UNSAFE_FUZZER_MODE)
Expand All @@ -22,13 +24,54 @@
#include <string.h>
#include <unistd.h>

#if defined(OPENSSL_LINUX)
#include <sys/syscall.h>
#endif

#include <openssl/thread.h>
#include <openssl/mem.h>

#include "internal.h"
#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|. */

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand All @@ -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;
}
Expand All @@ -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();
}
}
Expand Down
4 changes: 4 additions & 0 deletions include/openssl/base.h
Expand Up @@ -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
Expand Down

0 comments on commit 5e393fe

Please sign in to comment.