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.
This commit is contained in:
Wladimir J. van der Laan 2017-02-22 08:51:26 +01:00
parent 7cad849299
commit 7e6dcd9995
1 changed files with 34 additions and 15 deletions

View File

@ -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
}