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

Toke Høiland-Jørgensen toke at toke.dk
Wed Sep 23 18:03:15 CEST 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(), getentropy() and reading from
/dev/urandom.

Signed-off-by: Toke Høiland-Jørgensen <toke at toke.dk>
---
 conf/conf.c          |    1 +
 configure.ac         |    4 ++
 lib/birdlib.h        |    3 ++
 sysdep/unix/main.c   |    1 +
 sysdep/unix/random.c |   88 ++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 97 insertions(+)

diff --git a/conf/conf.c b/conf/conf.c
index b21d5213a..e353681d5 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);
+  random_close();
   shutting_down = 1;
 }
 
diff --git a/configure.ac b/configure.ac
index eabb3d562..d27bb327b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -373,6 +373,10 @@ elif test "$bird_cv_lib_log" != yes ; then
   LIBS="$LIBS $bird_cv_lib_log"
 fi
 
+AC_CHECK_FUNCS(getrandom)
+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 23036c1b1..61098f929 100644
--- a/lib/birdlib.h
+++ b/lib/birdlib.h
@@ -192,5 +192,8 @@ asm(
 /* Pseudorandom numbers */
 
 u32 random_u32(void);
+int random_bytes(char *buf, size_t size);
+void random_close(void);
+void random_init(void);
 
 #endif
diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c
index 2c7e3ceff..3903ecccb 100644
--- a/sysdep/unix/main.c
+++ b/sysdep/unix/main.c
@@ -851,6 +851,7 @@ main(int argc, char **argv)
   parse_args(argc, argv);
   log_switch(1, NULL, NULL);
 
+  random_init();
   net_init();
   resource_init();
   timer_init();
diff --git a/sysdep/unix/random.c b/sysdep/unix/random.c
index b1f5086fe..de81f3ca2 100644
--- a/sysdep/unix/random.c
+++ b/sysdep/unix/random.c
@@ -7,6 +7,21 @@
  */
 
 #include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.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
 
 #include "nest/bird.h"
 
@@ -19,3 +34,76 @@ random_u32(void)
   rand_high = random();
   return (rand_low & 0xffff) | ((rand_high & 0xffff) << 16);
 }
+
+void
+random_init()
+{
+  char buf;
+  /* get a single random byte to trip any errors early */
+  random_bytes(&buf, sizeof(buf));
+}
+
+#if defined(HAVE_GETRANDOM) || 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);
+#else
+    n = getentropy(buf, size);
+#endif
+    if (n < 0) {
+      if (errno == EINTR)
+        continue;
+      die("Couldn't get random bytes: %m");
+    }
+    buf += n;
+    size -= n;
+  }
+
+  return 0;
+}
+
+void random_close(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)
+      die("Couldn't open /dev/urandom: %m");
+  }
+
+  do
+  {
+    n = read(urandom_fd, buf, size);
+    if (n <= 0) {
+      if (errno == EINTR)
+        continue;
+      die("Couldn't read from /dev/urandom: %m");
+    }
+    buf += n;
+    size -= n;
+  } while (size > 0);
+
+  return 0;
+}
+
+void
+random_close(void)
+{
+  if (urandom_fd >= 0) {
+    close(urandom_fd);
+    urandom_fd = -1;
+  }
+}
+#endif



More information about the Bird-users mailing list