chiark / gitweb /
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 246a74a44587145eba36e17437422b5acdbaf187..631f78383d49a0bf4985f96784dd025103766068 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 6458f92dc355a21ccf143ebd7c34e09e1ad92f98..b59fd8ad99f4e2cbfe3de26c7a26964c815219c7 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 --- */