[PATCH 1/4] sysdep: Add wrapper to get random bytes

Toke Høiland-Jørgensen toke at toke.dk
Sun Feb 23 23:56:34 CET 2020


From: Toke Høiland-Jørgensen <toke at toke.dk>

The Babel authentication code added by a subsequent commit needs a way to
get random bytes for generating nonces.

This patch adds a wrapper function in sysdep to get random bytes, and the
required checks in configure.ac to select how to do it. The configure
script tries, in order, getrandom(), syscall(SYS_getrandom), getentropy()
and reading from /dev/urandom.

The order and methods corresponds to how CPython implements its
corresponding randomness functions.

Signed-off-by: Toke Høiland-Jørgensen <toke at toke.dk>
---
 aclocal.m4           |   49 +++++++++++++++++++++++++++++++
 conf/conf.c          |    1 +
 configure.ac         |   15 ++++++++++
 lib/birdlib.h        |    2 +
 sysdep/unix/random.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 145 insertions(+)

diff --git a/aclocal.m4 b/aclocal.m4
index 1613d680..0a1608cb 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -239,3 +239,52 @@ AC_DEFUN([BIRD_CHECK_BISON_VERSION],
       ;;
   esac
 ])
+
+# BIRD_CHECK_GETRANDOM_SYSCALL
+# Check for the getrandom syscall - borrowed from Python
+AC_DEFUN([BIRD_CHECK_GETRANDOM_SYSCALL], [{
+  # check if the Linux getrandom() syscall is available
+  # borrowed from the Python sources
+  AC_MSG_CHECKING(for the Linux getrandom() syscall)
+  AC_LINK_IFELSE(
+  [
+    AC_LANG_SOURCE([[
+      #include <unistd.h>
+      #include <sys/syscall.h>
+      #include <linux/random.h>
+
+      int main() {
+          char buffer[1];
+          const size_t buflen = sizeof(buffer);
+          const int flags = GRND_NONBLOCK;
+          int res = syscall(SYS_getrandom, buffer, buflen, flags);
+          return res == 0 ? 0 : 1;
+      }
+    ]])
+  ],[have_getrandom_syscall=yes],[have_getrandom_syscall=no])
+  AC_MSG_RESULT($have_getrandom_syscall)
+}])
+
+# BIRD_CHECK_GETRANDOM
+# Check for the getrandom function - borrowed from Python
+AC_DEFUN([BIRD_CHECK_GETRANDOM], [{
+  # check if the Linux getrandom() syscall is available
+  # borrowed from the Python sources
+  AC_MSG_CHECKING(for the getrandom() function)
+  AC_LINK_IFELSE(
+  [
+    AC_LANG_SOURCE([[
+    #include <sys/random.h>
+
+    int main() {
+        char buffer[1];
+        const size_t buflen = sizeof(buffer);
+        const int flags = 0;
+        int res = getrandom(buffer, buflen, flags);
+        return res == 0 ? 0 : 1;
+    }
+    ]])
+  ],[have_getrandom=yes],[have_getrandom=no])
+  AC_MSG_RESULT($have_getrandom)
+}])
+
diff --git a/conf/conf.c b/conf/conf.c
index b21d5213..65445579 100644
--- a/conf/conf.c
+++ b/conf/conf.c
@@ -515,6 +515,7 @@ order_shutdown(int gr)
   c->gr_down = gr;
 
   config_commit(c, RECONFIG_HARD, 0);
+  close_urandom();
   shutting_down = 1;
 }
 
diff --git a/configure.ac b/configure.ac
index da8546a6..4ebddfc3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -364,6 +364,21 @@ elif test "$bird_cv_lib_log" != yes ; then
   LIBS="$LIBS $bird_cv_lib_log"
 fi
 
+BIRD_CHECK_GETRANDOM_SYSCALL
+if test "$have_getrandom_syscall" = yes; then
+    AC_DEFINE(HAVE_GETRANDOM_SYSCALL, 1,
+              [Define to 1 if the Linux getrandom() syscall is available])
+fi
+
+BIRD_CHECK_GETRANDOM
+if test "$have_getrandom" = yes; then
+    AC_DEFINE(HAVE_GETRANDOM, 1,
+              [Define to 1 if the getrandom() function is available])
+fi
+
+AC_CHECK_FUNCS(getentropy)
+AC_CHECK_HEADERS(sys/random.h)
+
 if test "$enable_debug" = yes ; then
   AC_DEFINE([DEBUGGING], [1], [Define to 1 if debugging is enabled])
   LDFLAGS="$LDFLAGS -rdynamic"
diff --git a/lib/birdlib.h b/lib/birdlib.h
index 5202b0c8..7ce5fe3c 100644
--- a/lib/birdlib.h
+++ b/lib/birdlib.h
@@ -180,5 +180,7 @@ asm(
 /* Pseudorandom numbers */
 
 u32 random_u32(void);
+int random_bytes(char *buf, size_t size);
+void close_urandom(void);
 
 #endif
diff --git a/sysdep/unix/random.c b/sysdep/unix/random.c
index b1f5086f..6c8945fc 100644
--- a/sysdep/unix/random.c
+++ b/sysdep/unix/random.c
@@ -7,6 +7,23 @@
  */
 
 #include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "sysdep/config.h"
+
+#ifdef HAVE_SYS_STAT_H
+#  include <sys/stat.h>
+#endif
+#ifdef HAVE_LINUX_RANDOM_H
+#  include <linux/random.h>
+#endif
+#if defined(HAVE_SYS_RANDOM_H) && (defined(HAVE_GETRANDOM) || defined(HAVE_GETENTROPY))
+#    include <sys/random.h>
+#endif
+#if !defined(HAVE_GETRANDOM) && defined(HAVE_GETRANDOM_SYSCALL)
+#  include <sys/syscall.h>
+#endif
 
 #include "nest/bird.h"
 
@@ -19,3 +36,64 @@ random_u32(void)
   rand_high = random();
   return (rand_low & 0xffff) | ((rand_high & 0xffff) << 16);
 }
+
+#if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL) || defined(HAVE_GENTROPY)
+int
+random_bytes(char *buf, size_t size)
+{
+  int n;
+  int flags = 0;
+  while (0 < size) {
+#if defined(HAVE_GETRANDOM)
+    n = getrandom(buf, size, flags);
+#elif defined(HAVE_GETRANDOM_SYSCALL)
+    n = syscall(SYS_getrandom, buf, size, flags);
+#else
+    n = getentropy(buf, size);
+#endif
+    if (n < 0)
+      return -1;
+    buf += n;
+    size -= n;
+  }
+
+  return 0;
+}
+
+void close_urandom(void) {}
+
+#else
+
+static int urandom_fd = -1;
+int random_bytes(char *buf, size_t size)
+{
+  int n;
+
+  if (urandom_fd < 0)
+  {
+    urandom_fd = open("/dev/urandom", O_RDONLY);
+    if (urandom_fd < 0)
+      return -1;
+  }
+
+  do
+  {
+    n = read(urandom_fd, buf, size);
+    if (n <= 0)
+      return -1;
+    buf += n;
+    size -= n;
+  } while (size > 0);
+
+  return 0;
+}
+
+void
+close_urandom(void)
+{
+  if (urandom_fd >= 0) {
+    close(urandom_fd);
+    urandom_fd = -1;
+  }
+}
+#endif



More information about the Bird-users mailing list