diff mbox series

[for-4.1,2/7] util: Use getrandom for qemu_getrandom if available

Message ID 20190313062630.30568-3-richard.henderson@linaro.org
State New
Headers show
Series Add qemu_getrandom and ARMv8.5-RNG | expand

Commit Message

Richard Henderson March 13, 2019, 6:26 a.m. UTC
We only allow access to the "urandom" side of the interface,
and using -seed forces the use of the deterministic algorithm.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

---
 util/random.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++-----
 configure     | 18 +++++++++++-
 2 files changed, 88 insertions(+), 8 deletions(-)

-- 
2.17.1
diff mbox series

Patch

diff --git a/util/random.c b/util/random.c
index ded8725a3b..833169fad5 100644
--- a/util/random.c
+++ b/util/random.c
@@ -15,6 +15,13 @@ 
 #include "qapi/error.h"
 #include "qemu/random.h"
 
+#ifdef CONFIG_GETRANDOM
+# include <sys/random.h>
+static bool deterministic;
+#else
+#define deterministic  true
+#endif
+
 
 /*
  * While jrand48 is not technically thread safe, jrand48_r is glibc specific.
@@ -25,13 +32,11 @@ 
 static __thread uint16_t xsubi[3];
 
 /* Deterministic implementation using libc functions.  */
-bool qemu_getrandom(void *buf, size_t len, bool nonblock)
+static bool do_jrand48(void *buf, size_t len, bool nonblock)
 {
     size_t i;
     uint32_t val;
 
-    g_assert_cmpuint(len, <=, 256);
-
     for (i = 0; i + 4 <= len; i += 4) {
         val = jrand48(xsubi);
         __builtin_memcpy(buf + i, &val, 4);
@@ -44,18 +49,63 @@  bool qemu_getrandom(void *buf, size_t len, bool nonblock)
     return true;
 }
 
+#ifdef CONFIG_GETRANDOM
+static bool do_getrandom(void *buf, size_t len, bool nonblock)
+{
+    while (len != 0) {
+        ssize_t ret = getrandom(buf, len, nonblock ? GRND_NONBLOCK : 0);
+        if (unlikely(ret < 0)) {
+            switch (errno) {
+            case EAGAIN:
+                /* Only returned for GRND_NONBLOCK. */
+                return false;
+            case EINTR:
+                /* Signal.  Just try again.  */
+                break;
+            default:
+                /* EFAULT or EINVAL; either a bug in the user or here. */
+                g_assert_not_reached();
+            }
+        } else {
+            len -= ret;
+            buf += ret;
+        }
+    }
+    return true;
+}
+#endif
+
+bool qemu_getrandom(void *buf, size_t len, bool nonblock)
+{
+    /* Assert the interface contract is honored.  */
+    g_assert_cmpuint(len, <=, 256);
+
+    if (!deterministic) {
+#ifdef CONFIG_GETRANDOM
+        return do_getrandom(buf, len, nonblock);
+#endif
+    }
+    return do_jrand48(buf, len, nonblock);
+}
+
 uint64_t qemu_seedrandom_thread_part1(void)
 {
     uint64_t ret;
-    qemu_getrandom(&ret, sizeof(ret), false);
+    if (deterministic) {
+        qemu_getrandom(&ret, sizeof(ret), false);
+    } else {
+        ret = 0;
+    }
     return ret;
 }
 
 void qemu_seedrandom_thread_part2(uint64_t seed)
 {
-    xsubi[0] = seed;
-    xsubi[1] = seed >> 16;
-    xsubi[2] = seed >> 32;
+    if (deterministic) {
+        xsubi[0] = seed;
+        xsubi[1] = seed >> 16;
+        xsubi[2] = seed >> 32;
+    }
 }
 
 void qemu_seedrandom_main(const char *optarg, Error **errp)
@@ -64,6 +114,9 @@  void qemu_seedrandom_main(const char *optarg, Error **errp)
     if (parse_uint_full(optarg, &seed, 0)) {
         error_setg(errp, "Invalid seed number: %s", optarg);
     } else {
+#ifndef deterministic
+        deterministic = true;
+#endif
         qemu_seedrandom_thread_part2(seed);
     }
 }
@@ -72,5 +125,16 @@  static void __attribute__((constructor)) initialize(void)
 {
     /* Make sure A and C parameters are initialized.  */
     srand48(0);
+
+#ifdef CONFIG_GETRANDOM
+    /* Make sure support exists within the running kernel.  */
+    errno = 0;
+    if (getrandom(NULL, 0, 0) == 0) {
+        return;
+    }
+    g_assert_cmpint(errno, ==, ENOSYS);
+    deterministic = true;
+#endif
+
     qemu_seedrandom_thread_part2(time(NULL) + getpid() * 1500450271ull);
 }
diff --git a/configure b/configure
index cab830a4c9..22c7944e38 100755
--- a/configure
+++ b/configure
@@ -5700,6 +5700,20 @@  if compile_prog "" "" ; then
     have_utmpx=yes
 fi
 
+##########################################
+# check for getrandom()
+
+have_getrandom=no
+cat > $TMPC << EOF
+#include <sys/random.h>
+int main(void) {
+    return getrandom(0, 0, GRND_NONBLOCK);
+}
+EOF
+if compile_prog "" "" ; then
+    have_getrandom=yes
+fi
+
 ##########################################
 # checks for sanitizers
 
@@ -7073,7 +7087,9 @@  fi
 if test "$have_utmpx" = "yes" ; then
   echo "HAVE_UTMPX=y" >> $config_host_mak
 fi
-
+if test "$have_getrandom" = "yes" ; then
+  echo "CONFIG_GETRANDOM=y" >> $config_host_mak
+fi
 if test "$ivshmem" = "yes" ; then
   echo "CONFIG_IVSHMEM=y" >> $config_host_mak
 fi