From 74f7872f89dc8ecad500c5d5c4e03b4757f6418d Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 13 Dec 2016 22:59:31 +0100 Subject: [PATCH] Rearrange RNG code slightly In preparation of exporting getentropy/getrandom to userspace, rearrange code a bit: - Define RtlGenRandom in ntdll.h. - Drop calls to getentropy in favor of RtlGenRandom (fhandler_socket, fhandler_dev_random). - Add try/except blocks in fhandler_dev_random to return EFAULT rather than crashing if buffer pointer is invalid. Signed-off-by: Corinna Vinschen --- winsup/cygwin/fhandler_random.cc | 72 ++++++++++++++++++++------------ winsup/cygwin/fhandler_socket.cc | 2 +- winsup/cygwin/miscfuncs.cc | 6 --- winsup/cygwin/ntdll.h | 6 +++ 4 files changed, 52 insertions(+), 34 deletions(-) diff --git a/winsup/cygwin/fhandler_random.cc b/winsup/cygwin/fhandler_random.cc index af76a6614..c56ce73d3 100644 --- a/winsup/cygwin/fhandler_random.cc +++ b/winsup/cygwin/fhandler_random.cc @@ -47,16 +47,26 @@ fhandler_dev_random::write (const void *ptr, size_t len) } /* Limit len to a value <= 4096 since we don't want to overact. - Copy to local buffer because CryptGenRandom violates const. */ + Copy to local buffer because RtlGenRandom violates const. */ size_t limited_len = MIN (len, 4096); unsigned char buf[limited_len]; - memcpy (buf, ptr, limited_len); /* Mess up system entropy source. Return error if device is /dev/random. */ - if (getentropy (buf, limited_len) && dev () == FH_RANDOM) - return -1; - /* Mess up the pseudo random number generator. */ - pseudo_write (buf, limited_len); + __try + { + memcpy (buf, ptr, limited_len); + if (!RtlGenRandom (buf, limited_len) && dev () == FH_RANDOM) + return -1; + /* Mess up the pseudo random number generator. */ + pseudo_write (buf, limited_len); + } + __except (EFAULT) + { + len = -1; + } + __endtry + /* Note that we return len, not limited_len. No reason to confuse the + caller... */ return len; } @@ -88,32 +98,40 @@ fhandler_dev_random::read (void *ptr, size_t& len) return; } - /* /dev/random has to provide high quality random numbers. Therefore we - re-seed the system PRNG for each block of 512 bytes. This results in - sufficiently random sequences, comparable to the Linux /dev/random. */ - if (dev () == FH_RANDOM) + __try { - void *dummy = malloc (RESEED_INTERVAL); - if (!dummy) + /* /dev/random has to provide high quality random numbers. Therefore we + re-seed the system PRNG for each block of 512 bytes. This results in + sufficiently random sequences, comparable to the Linux /dev/random. */ + if (dev () == FH_RANDOM) { - __seterrno (); - len = (size_t) -1; - return; - } - for (size_t offset = 0; offset < len; offset += 512) - { - if (getentropy (dummy, RESEED_INTERVAL) || - getentropy ((PBYTE) ptr + offset, len - offset)) + void *dummy = malloc (RESEED_INTERVAL); + if (!dummy) { + __seterrno (); len = (size_t) -1; - break; + return; } + for (size_t offset = 0; offset < len; offset += 512) + { + if (!RtlGenRandom (dummy, RESEED_INTERVAL) || + !RtlGenRandom ((PBYTE) ptr + offset, len - offset)) + { + len = (size_t) -1; + break; + } + } + free (dummy); } - free (dummy); - } - /* If device is /dev/urandom, just use system RNG as is, with our own - PRNG as fallback. */ - else if (getentropy (ptr, len)) - len = pseudo_read (ptr, len); + /* If device is /dev/urandom, just use system RNG as is, with our own + PRNG as fallback. */ + else if (!RtlGenRandom (ptr, len)) + len = pseudo_read (ptr, len); + } + __except (EFAULT) + { + len = (size_t) -1; + } + __endtry } diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index 9ada4697d..801a731a5 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -485,7 +485,7 @@ fhandler_socket::af_local_copy (fhandler_socket *sock) void fhandler_socket::af_local_set_secret (char *buf) { - if (getentropy (connect_secret, sizeof (connect_secret))) + if (!RtlGenRandom (connect_secret, sizeof (connect_secret))) bzero ((char*) connect_secret, sizeof (connect_secret)); __small_sprintf (buf, "%08x-%08x-%08x-%08x", connect_secret [0], connect_secret [1], diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc index f90d6efa2..0b19b2892 100644 --- a/winsup/cygwin/miscfuncs.cc +++ b/winsup/cygwin/miscfuncs.cc @@ -233,12 +233,6 @@ check_iovec (const struct iovec *iov, int iovcnt, bool forwrite) return -1; } -/* There's a bug in ntsecapi.h (Mingw as well as MSFT). SystemFunction036 - is, in fact, a WINAPI function, but it's not defined as such. Therefore - we have to do it correctly here. */ -#define RtlGenRandom SystemFunction036 -extern "C" BOOLEAN WINAPI RtlGenRandom (PVOID, ULONG); - /* Used by arc2random, fhandler_socket and fhandler_random. */ extern "C" int getentropy (void *ptr, size_t len) diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index 448eadf20..bf5a7cf80 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -1608,4 +1608,10 @@ extern "C" } } + +/* There's a bug in ntsecapi.h (Mingw as well as MSFT). SystemFunction036 + is, in fact, a WINAPI function, but it's not defined as such. Therefore + we have to do it correctly here. *Strictly*, this is not ntdll... */ +#define RtlGenRandom SystemFunction036 +extern "C" BOOLEAN WINAPI RtlGenRandom (PVOID, ULONG); #endif