mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-09 12:28:19 -04:00
Seed the RNG using sysctl() as well as /dev/urandom
William Ahern points out that if the user has chrooted, they might not have a working /dev/urandom. Linux and many of the BSDs, however, define a sysctl interface to their kernel random number generators. This patch takes a belt-and-suspenders approach and tries to do use the sysctl _and_ the /dev/urandom approach if both are present. When using the sysctl approach, it tries to bulletproof itself by checking to make sure that the buffers are actually set by the sysctl calls.
This commit is contained in:
parent
b1c795007f
commit
71fc3eb08b
146
arc4random.c
146
arc4random.c
@ -1,5 +1,6 @@
|
||||
/* Portable arc4random.c based on arc4random.c from OpenBSD.
|
||||
* Portable version by Chris Davis, adapted for Libevent by Nick Mathewson
|
||||
* Copyright (c) 2010 Chris Davis, Niels Provos, and Nick Mathewson
|
||||
*
|
||||
* Note that in Libevent, this file isn't compiled directly. Instead,
|
||||
* it's included from evutil_rand.c
|
||||
@ -56,6 +57,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
@ -135,29 +137,20 @@ read_all(int fd, unsigned char *buf, size_t count)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This is adapted from Tor's crypto_seed_rng() */
|
||||
static int
|
||||
arc4_seed(void)
|
||||
{
|
||||
unsigned char buf[ADD_ENTROPY];
|
||||
|
||||
/* local variables */
|
||||
#ifdef WIN32
|
||||
#define TRY_SEED_WIN32
|
||||
static int
|
||||
arc4_seed_win32(void)
|
||||
{
|
||||
/* This is adapted from Tor's crypto_seed_rng() */
|
||||
static int provider_set = 0;
|
||||
static HCRYPTPROV provider;
|
||||
#else
|
||||
static const char *filenames[] = {
|
||||
"/dev/srandom", "/dev/urandom", "/dev/random", NULL
|
||||
};
|
||||
int fd, i;
|
||||
size_t n;
|
||||
#endif
|
||||
unsigned char buf[ADD_ENTROPY];
|
||||
|
||||
#ifdef WIN32
|
||||
if (!provider_set) {
|
||||
if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT)) {
|
||||
if ((unsigned long)GetLastError() != (unsigned long)NTE_BAD_KEYSET)
|
||||
if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
|
||||
return -1;
|
||||
}
|
||||
provider_set = 1;
|
||||
@ -168,7 +161,100 @@ arc4_seed(void)
|
||||
memset(buf, 0, sizeof(buf));
|
||||
arc4_seeded_ok = 1;
|
||||
return 0;
|
||||
#else
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_EVENT_HAVE_SYS_SYSCTL_H)
|
||||
#if _EVENT_HAVE_DECL_CTL_KERN && _EVENT_HAVE_DECL_KERN_RANDOM && _EVENT_HAVE_DECL_RANDOM_UUID
|
||||
#define TRY_SEED_SYSCTL_LINUX
|
||||
static int
|
||||
arc4_seed_sysctl_linux(void)
|
||||
{
|
||||
/* Based on code by William Ahern, this function tries to use the
|
||||
* RANDOM_UUID sysctl to get entropy from the kernel. This can work
|
||||
* even if /dev/urandom is inaccessible for some reason (e.g., we're
|
||||
* running in a chroot). */
|
||||
int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID };
|
||||
unsigned char buf[ADD_ENTROPY];
|
||||
size_t len, n;
|
||||
int i, any_set;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
for (len = 0; len < sizeof(buf); len += n) {
|
||||
n = sizeof(buf) - len;
|
||||
|
||||
if (0 != sysctl(mib, 3, &buf[len], &n, NULL, 0))
|
||||
return -1;
|
||||
}
|
||||
/* make sure that the buffer actually got set. */
|
||||
for (i=any_set=0; i<sizeof(buf); ++i) {
|
||||
any_set |= buf[i];
|
||||
}
|
||||
if (!any_set)
|
||||
return -1;
|
||||
|
||||
arc4_addrandom(buf, sizeof(buf));
|
||||
memset(buf, 0, sizeof(buf));
|
||||
arc4_seeded_ok = 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _EVENT_HAVE_DECL_CTL_KERN && _EVENT_HAVE_DECL_KERN_ARAND
|
||||
#define TRY_SEED_SYSCTL_BSD
|
||||
static int
|
||||
arc4_seed_sysctl_bsd(void)
|
||||
{
|
||||
/* Based on code from William Ahern and from OpenBSD, this function
|
||||
* tries to use the KERN_ARAND syscall to get entropy from the kernel.
|
||||
* This can work even if /dev/urandom is inaccessible for some reason
|
||||
* (e.g., we're running in a chroot). */
|
||||
int mib[] = { CTL_KERN, KERN_ARAND };
|
||||
unsigned char buf[ADD_ENTROPY];
|
||||
size_t len, n;
|
||||
int i, any_set;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
len = sizeof(buf);
|
||||
if (sysctl(mib, 2, rnd, &len, NULL, 0) == -1) {
|
||||
for (len = 0; len < sizeof(buf); len += sizeof(unsigned)) {
|
||||
n = sizeof(unsigned);
|
||||
if (n + len > sizeof(buf))
|
||||
n = len - sizeof(buf);
|
||||
if (sysctl(mib, 2, &buf[len], &n, NULL, 0) == -1)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* make sure that the buffer actually got set. */
|
||||
for (i=any_set=0; i<sizeof(buf); ++i) {
|
||||
any_set |= buf[i];
|
||||
}
|
||||
if (!any_set)
|
||||
return -1;
|
||||
|
||||
arc4_addrandom(buf, sizeof(buf));
|
||||
memset(buf, 0, sizeof(buf));
|
||||
arc4_seeded_ok = 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif /* defined(_EVENT_HAVE_SYS_SYSCTL_H) */
|
||||
|
||||
#ifndef WIN32
|
||||
#define TRY_SEED_URANDOM
|
||||
static int
|
||||
arc4_seed_urandom(void)
|
||||
{
|
||||
/* This is adapted from Tor's crypto_seed_rng() */
|
||||
static const char *filenames[] = {
|
||||
"/dev/srandom", "/dev/urandom", "/dev/random", NULL
|
||||
};
|
||||
unsigned char buf[ADD_ENTROPY];
|
||||
int fd, i;
|
||||
size_t n;
|
||||
|
||||
for (i = 0; filenames[i]; ++i) {
|
||||
fd = open(filenames[i], O_RDONLY, 0);
|
||||
if (fd<0)
|
||||
@ -184,7 +270,33 @@ arc4_seed(void)
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
arc4_seed(void)
|
||||
{
|
||||
int ok = 0;
|
||||
/* We try every method that might work, and don't give up even if one
|
||||
* does seem to work. There's no real harm in over-seeding, and if
|
||||
* one of these sources turns out to be broken, that would be bad. */
|
||||
#ifdef TRY_SEED_WIN32
|
||||
if (0 == arc4_seed_win32())
|
||||
ok = 1;
|
||||
#endif
|
||||
#ifdef TRY_SEED_SYSCTL_LINUX
|
||||
if (0 == arc4_seed_sysctl_linux())
|
||||
ok = 1;
|
||||
#endif
|
||||
#ifdef TRY_SEED_SYSCTL_BSD
|
||||
if (0 == arc4_seed_sysctl_bsd())
|
||||
ok = 1;
|
||||
#endif
|
||||
#ifdef TRY_SEED_URANDOM
|
||||
if (0 == arc4_seed_urandom())
|
||||
ok = 1;
|
||||
#endif
|
||||
return ok ? 0 : -1;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -86,7 +86,7 @@ AC_SUBST(OPENSSL_LIBS)
|
||||
|
||||
dnl Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS(fcntl.h stdarg.h inttypes.h stdint.h stddef.h poll.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/param.h sys/ioctl.h sys/select.h sys/devpoll.h port.h netinet/in.h netinet/in6.h sys/socket.h sys/uio.h arpa/inet.h sys/eventfd.h sys/mman.h sys/sendfile.h netdb.h)
|
||||
AC_CHECK_HEADERS(fcntl.h stdarg.h inttypes.h stdint.h stddef.h poll.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/param.h sys/ioctl.h sys/select.h sys/devpoll.h port.h netinet/in.h netinet/in6.h sys/socket.h sys/uio.h arpa/inet.h sys/eventfd.h sys/mman.h sys/sendfile.h netdb.h sys/sysctl.h)
|
||||
if test "x$ac_cv_header_sys_queue_h" = "xyes"; then
|
||||
AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h)
|
||||
AC_EGREP_CPP(yes,
|
||||
@ -158,6 +158,12 @@ if test "x$ac_cv_header_sys_time_h" = "xyes"; then
|
||||
)
|
||||
fi
|
||||
|
||||
if test "x$ac_cv_header_sys_sysctl_h" = "xyes"; then
|
||||
AC_CHECK_DECLS([CTL_KERN, KERN_RANDOM, RANDOM_UUID, KERN_ARAND], [], [],
|
||||
[[#include <sys/sysctl.h>]]
|
||||
)
|
||||
fi
|
||||
|
||||
dnl - check if the macro WIN32 is defined on this compiler.
|
||||
dnl - (this is how we check for a windows version of GCC)
|
||||
AC_MSG_CHECKING(for WIN32)
|
||||
|
Loading…
x
Reference in New Issue
Block a user