rand/noise.c (noise_devrandom): Use new Linux system call `getrandom'.
authorMark Wooding <mdw@distorted.org.uk>
Thu, 26 May 2016 08:26:09 +0000 (09:26 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 4 Jun 2016 13:55:30 +0000 (14:55 +0100)
The new system call has pretty much the right semantics.  If it's
available, then try to use it.  Annoyingly, the syscall isn't supported
in the libc, so we have to do it the hard way.  On the plus side, this
means that the code will work if built on a system with the syscall
defined, and run on one with the right kernel, without introducing a
dependency on the libc.

If it fails because the kernel entropy pool isn't initialized, then
there's no point in messing with the devices because they won't be any
better.  If it fails because the call isn't there, then it proceeds with
other options.

configure.ac
rand/noise.c

index 246a74a..631f783 100644 (file)
@@ -221,6 +221,7 @@ AC_SUBST([limits])
 
 dnl Functions used for noise-gathering.
 AC_CHECK_FUNCS([setgroups])
+AC_CHECK_HEADERS([linux/random.h])
 AC_CACHE_CHECK([whether the freewheel noise generator will work],
        [catacomb_cv_freewheel],
 [AC_TRY_LINK(
index 6458f92..b59fd8a 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "config.h"
 
+#include <errno.h>
 #include <setjmp.h>
 #include <signal.h>
 #include <stdio.h>
 #  include <grp.h>
 #endif
 
+#if defined(HAVE_LINUX_RANDOM_H)
+#  include <linux/random.h>
+#  include <sys/syscall.h>
+#endif
+
 #include <mLib/bits.h>
 #include <mLib/mdup.h>
 #include <mLib/sel.h>
@@ -167,6 +173,22 @@ int noise_devrandom(rand_pool *r)
   struct timeval tv = { 0, 0 };
 #endif
 
+#if defined(HAVE_LINUX_RANDOM_H) &&                                    \
+    defined(GRND_NONBLOCK) &&                                          \
+    defined(SYS_getrandom)
+  /* --- Use the new shinies if available --- */
+
+  while (n < sizeof(buf)) {
+    if ((len = syscall(SYS_getrandom, buf + n, sizeof(buf) - n,
+                      GRND_NONBLOCK)) <= 0) {
+      if (errno == ENOSYS) break;
+      else goto done;
+    }
+    n += len;
+  }
+  if (n == sizeof(buf)) goto win;
+#endif
+
 #ifdef __linux__
   /* --- Don't take from `/dev/urandom' if `/dev/random' would block --- */