From 7e6dcd9995b99e894b8017f09016c405b066ca36 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 22 Feb 2017 08:51:26 +0100 Subject: random: Add fallback if getrandom syscall not available If the code was compiled with newer (>=3.17) kernel headers but executed on a system without the system call, every use of random would crash the program. Add a fallback for that case. --- src/random.cpp | 49 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 15 deletions(-) (limited to 'src/random.cpp') diff --git a/src/random.cpp b/src/random.cpp index 7fdada7525..8284f457c9 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -102,6 +102,28 @@ static void RandAddSeedPerfmon() #endif } +#ifndef WIN32 +/** Fallback: get 32 bytes of system entropy from /dev/urandom. The most + * compatible way to get cryptographic randomness on UNIX-ish platforms. + */ +void GetDevURandom(unsigned char *ent32) +{ + int f = open("/dev/urandom", O_RDONLY); + if (f == -1) { + RandFailure(); + } + int have = 0; + do { + ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have); + if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) { + RandFailure(); + } + have += n; + } while (have < NUM_OS_RANDOM_BYTES); + close(f); +} +#endif + /** Get 32 bytes of system entropy. */ void GetOSRand(unsigned char *ent32) { @@ -122,8 +144,17 @@ void GetOSRand(unsigned char *ent32) * will always return as many bytes as requested and will not be * interrupted by signals." */ - if (syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0) != NUM_OS_RANDOM_BYTES) { - RandFailure(); + int rv = syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0); + if (rv != NUM_OS_RANDOM_BYTES) { + if (rv < 0 && errno == ENOSYS) { + /* Fallback for kernel <3.17: the return value will be -1 and errno + * ENOSYS if the syscall is not available, in that case fall back + * to /dev/urandom. + */ + GetDevURandom(ent32); + } else { + RandFailure(); + } } #elif defined(HAVE_GETENTROPY) /* On OpenBSD this can return up to 256 bytes of entropy, will return an @@ -150,19 +181,7 @@ void GetOSRand(unsigned char *ent32) /* Fall back to /dev/urandom if there is no specific method implemented to * get system entropy for this OS. */ - int f = open("/dev/urandom", O_RDONLY); - if (f == -1) { - RandFailure(); - } - int have = 0; - do { - ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have); - if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) { - RandFailure(); - } - have += n; - } while (have < NUM_OS_RANDOM_BYTES); - close(f); + GetDevURandom(ent32); #endif } -- cgit v1.2.3