Commit 3b3588b4 authored by Chris Palmer's avatar Chris Palmer Committed by Commit Bot

[base] Use getrandom on Linux.

Fall back to reading from urandom only when that fails.

This is a re-land of
https://chromium-review.googlesource.com/c/chromium/src/+/1762604, which was
reverted in https://chromium-review.googlesource.com/c/chromium/src/+/2377418.

Bug: 995996
Change-Id: I007581630f789881ab956c1b1666b99f087fa154
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2380673Reviewed-by: default avatarJulien Tinnes <jln@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Commit-Queue: Chris Palmer <palmer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#802691}
parent 335fab93
...@@ -11,37 +11,40 @@ ...@@ -11,37 +11,40 @@
#include <unistd.h> #include <unistd.h>
#include "base/check.h" #include "base/check.h"
#include "base/compiler_specific.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/no_destructor.h" #include "base/no_destructor.h"
#include "base/posix/eintr_wrapper.h" #include "base/posix/eintr_wrapper.h"
#include "build/build_config.h" #include "build/build_config.h"
#if defined(OS_MAC) #if defined(OS_LINUX) || defined(OS_CHROMEOS)
#include "third_party/lss/linux_syscall_support.h"
#endif
#if !defined(OS_IOS) && !defined(OS_NACL)
// TODO(crbug.com/995996): Waiting for this header to appear in the iOS SDK. // TODO(crbug.com/995996): Waiting for this header to appear in the iOS SDK.
// (See below.) We'll also use this on other POSIX platforms in the future (and // (See below.)
// change the #if condition then).
#include <sys/random.h> #include <sys/random.h>
#endif #endif
namespace { namespace {
#if defined(OS_AIX)
// AIX has no 64-bit support for O_CLOEXEC.
static constexpr int kOpenFlags = O_RDONLY;
#else
static constexpr int kOpenFlags = O_RDONLY | O_CLOEXEC;
#endif
// We keep the file descriptor for /dev/urandom around so we don't need to // We keep the file descriptor for /dev/urandom around so we don't need to
// reopen it (which is expensive), and since we may not even be able to reopen // reopen it (which is expensive), and since we may not even be able to reopen
// it if we are later put in a sandbox. This class wraps the file descriptor so // it if we are later put in a sandbox. This class wraps the file descriptor so
// we can use a static-local variable to handle opening it on the first access. // we can use a static-local variable to handle opening it on the first access.
class URandomFd { class URandomFd {
public: public:
#if defined(OS_AIX) URandomFd() : fd_(HANDLE_EINTR(open("/dev/urandom", kOpenFlags))) {
// AIX has no 64-bit support for open falgs such as - CHECK(fd_ >= 0) << "Cannot open /dev/urandom";
// O_CLOEXEC, O_NOFOLLOW and O_TTY_INIT
URandomFd() : fd_(HANDLE_EINTR(open("/dev/urandom", O_RDONLY))) {
DPCHECK(fd_ >= 0) << "Cannot open /dev/urandom";
}
#else
URandomFd() : fd_(HANDLE_EINTR(open("/dev/urandom", O_RDONLY | O_CLOEXEC))) {
DPCHECK(fd_ >= 0) << "Cannot open /dev/urandom";
} }
#endif
~URandomFd() { close(fd_); } ~URandomFd() { close(fd_); }
...@@ -55,8 +58,25 @@ class URandomFd { ...@@ -55,8 +58,25 @@ class URandomFd {
namespace base { namespace base {
// NOTE: In an ideal future, all implementations of this function will just
// wrap BoringSSL's `RAND_bytes`. TODO(crbug.com/995996): Figure out the
// build/test/performance issues with dcheng's CL
// (https://chromium-review.googlesource.com/c/chromium/src/+/1545096) and land
// it or some form of it.
void RandBytes(void* output, size_t output_length) { void RandBytes(void* output, size_t output_length) {
#if defined(OS_MAC) #if (defined(OS_LINUX) || defined(OS_CHROMEOS)) && !defined(OS_NACL)
// We have to call `getrandom` via Linux Syscall Support, rather than through
// the libc wrapper, because we might not have an up-to-date libc (e.g. on
// some bots).
const ssize_t r = HANDLE_EINTR(sys_getrandom(output, output_length, 0));
// Return success only on total success. In case errno == ENOSYS (or any other
// error), we'll fall through to reading from urandom below.
if (output_length == static_cast<size_t>(r)) {
MSAN_UNPOISON(output, output_length);
return;
}
#elif defined(OS_MAC)
// TODO(crbug.com/995996): Enable this on iOS too, when sys/random.h arrives // TODO(crbug.com/995996): Enable this on iOS too, when sys/random.h arrives
// in its SDK. // in its SDK.
if (__builtin_available(macOS 10.12, *)) { if (__builtin_available(macOS 10.12, *)) {
...@@ -64,9 +84,13 @@ void RandBytes(void* output, size_t output_length) { ...@@ -64,9 +84,13 @@ void RandBytes(void* output, size_t output_length) {
return; return;
} }
} }
// Fall through to reading from urandom on < 10.12:
#endif #endif
// If the OS-specific mechanisms didn't work, fall through to reading from
// urandom.
//
// TODO(crbug.com/995996): When we no longer need to support old Linux
// kernels, we can get rid of this /dev/urandom branch altogether.
const int urandom_fd = GetUrandomFD(); const int urandom_fd = GetUrandomFD();
const bool success = const bool success =
ReadFromFD(urandom_fd, static_cast<char*>(output), output_length); ReadFromFD(urandom_fd, static_cast<char*>(output), output_length);
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "base/files/scoped_file.h" #include "base/files/scoped_file.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/posix/eintr_wrapper.h" #include "base/posix/eintr_wrapper.h"
#include "base/rand_util.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "components/nacl/common/nacl_switches.h" #include "components/nacl/common/nacl_switches.h"
#include "components/nacl/loader/nonsfi/nonsfi_sandbox.h" #include "components/nacl/loader/nonsfi/nonsfi_sandbox.h"
...@@ -127,6 +128,11 @@ void NaClSandbox::InitializeLayerOneSandbox() { ...@@ -127,6 +128,11 @@ void NaClSandbox::InitializeLayerOneSandbox() {
// Check that IsSandboxed() works. We should not be sandboxed at this point. // Check that IsSandboxed() works. We should not be sandboxed at this point.
CHECK(!IsSandboxed()) << "Unexpectedly sandboxed!"; CHECK(!IsSandboxed()) << "Unexpectedly sandboxed!";
// Open /dev/urandom while we can. This enables `base::RandBytes` to work. We
// don't need to store the resulting file descriptor; it's a singleton and
// subsequent calls to `GetUrandomFD` will return it.
CHECK_GE(base::GetUrandomFD(), 0);
if (setuid_sandbox_client_->IsSuidSandboxChild()) { if (setuid_sandbox_client_->IsSuidSandboxChild()) {
setuid_sandbox_client_->CloseDummyFile(); setuid_sandbox_client_->CloseDummyFile();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment