diff options
author | Toke Høiland-Jørgensen <toke@toke.dk> | 2021-04-01 19:20:13 +0200 |
---|---|---|
committer | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2021-06-06 16:26:06 +0200 |
commit | c48ebde5ce6db3da8cd571d213d1a1f265de8983 (patch) | |
tree | e465e1372465923b1123fd3957218eae84432868 | |
parent | 91d04583891f7a6f4aee612cf3f143cc84a73991 (diff) |
sysdep: Add wrapper to get random bytes
Add a wrapper function in sysdep to get random bytes, and required checks
in configure.ac to select how to do it. The configure script tries, in
order, getrandom(), getentropy() and reading from /dev/urandom.
-rw-r--r-- | conf/conf.c | 1 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | lib/birdlib.h | 3 | ||||
-rw-r--r-- | sysdep/unix/main.c | 1 | ||||
-rw-r--r-- | sysdep/unix/random.c | 88 |
5 files changed, 97 insertions, 0 deletions
diff --git a/conf/conf.c b/conf/conf.c index 58abcde1..0c355be4 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -524,6 +524,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 7d92a5d4..ded258d3 100644 --- a/configure.ac +++ b/configure.ac @@ -374,6 +374,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 23036c1b..61098f92 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 76f92c5e..392aff9d 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -867,6 +867,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 b1f5086f..de81f3ca 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 |