From: Toke Høiland-Jørgensen <[email protected]> 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 <[email protected]> --- 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
