random: use getrandom() on Linux where available
authorDaniel Kahn Gillmor <dkg@fifthhorseman.net>
Wed, 5 Sep 2018 14:34:04 +0000 (10:34 -0400)
committerWerner Koch <wk@gnupg.org>
Fri, 26 Oct 2018 11:37:11 +0000 (13:37 +0200)
* random/rndlinux.c (_gcry_rndlinux_gather_random): use the
getrandom() syscall on Linux if it exists, regardless of what kind of
entropy was requested.

--

This change avoids the serious usability problem of unnecessary
blocking on /dev/random when the kernel's PRNG is already seeded,
without introducing the risk of pulling from an uninitialized PRNG.
It only has an effect on Linux systems with a functioning getrandom()
syscall.  If that syscall is unavailable or fails, it should fall
through to the pre-existing behavior.

GnuPG-bug-id: 3894
Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
random/rndlinux.c

index f70bc21..fefc3c3 100644 (file)
@@ -245,17 +245,16 @@ _gcry_rndlinux_gather_random (void (*add)(const void*, size_t,
       struct timeval tv;
       int rc;
 
-      /* If we have a modern Linux kernel and we want to read from the
-       * the non-blocking /dev/urandom, we first try to use the new
+      /* If we have a modern Linux kernel, we first try to use the new
        * getrandom syscall.  That call guarantees that the kernel's
        * RNG has been properly seeded before returning any data.  This
        * is different from /dev/urandom which may, due to its
        * non-blocking semantics, return data even if the kernel has
-       * not been properly seeded.  Unfortunately we need to use a
+       * not been properly seeded.  And it differs from /dev/random by never
+       * blocking once the kernel is seeded. Unfortunately we need to use a
        * syscall and not a new device and thus we are not able to use
        * select(2) to have a timeout. */
 #if defined(__linux__) && defined(HAVE_SYSCALL) && defined(__NR_getrandom)
-      if (fd == fd_urandom)
         {
           long ret;
           size_t nbytes;
@@ -272,7 +271,7 @@ _gcry_rndlinux_gather_random (void (*add)(const void*, size_t,
             }
           while (ret == -1 && errno == EINTR);
           if (ret == -1 && errno == ENOSYS)
-            ; /* The syscall is not supported - fallback to /dev/urandom.  */
+            ; /* The syscall is not supported - fallback to pulling from fd.  */
           else
             { /* The syscall is supported.  Some sanity checks.  */
               if (ret == -1)