# HG changeset patch # User Matt Johnston # Date 1590677441 -28800 # Node ID f966834f0f9ce63d742172579b5f83e402d04740 # Parent 789466c5956b1d60b343ed9cc090f71a72c587f5 Use Linux getrandom() to ensure random device is initialised Remove old code warning about random device being not ready, /dev/random isn't used by default anyway. diff -r 789466c5956b -r f966834f0f9c configure.ac --- a/configure.ac Thu May 28 22:02:33 2020 +0800 +++ b/configure.ac Thu May 28 22:50:41 2020 +0800 @@ -370,7 +370,8 @@ crypt.h \ pty.h libutil.h libgen.h inttypes.h stropts.h utmp.h \ utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h \ - pam/pam_appl.h netinet/in_systm.h sys/uio.h linux/pkt_sched.h]) + pam/pam_appl.h netinet/in_systm.h sys/uio.h linux/pkt_sched.h \ + sys/random.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -526,7 +527,7 @@ AC_CHECK_HEADERS([mach/mach_time.h]) AC_CHECK_FUNCS(mach_absolute_time) -AC_CHECK_FUNCS(explicit_bzero memset_s) +AC_CHECK_FUNCS(explicit_bzero memset_s getrandom) AC_ARG_ENABLE(bundled-libtom, [ --enable-bundled-libtom Force using bundled libtomcrypt/libtommath even if a system version exists. diff -r 789466c5956b -r f966834f0f9c dbrandom.c --- a/dbrandom.c Thu May 28 22:02:33 2020 +0800 +++ b/dbrandom.c Thu May 28 22:50:41 2020 +0800 @@ -49,24 +49,19 @@ * */ -/* Pass len=0 to hash an entire file */ +/* Pass wantlen=0 to hash an entire file */ static int process_file(hash_state *hs, const char *filename, - unsigned int len, int prngd) -{ - static int already_blocked = 0; + unsigned int wantlen, int prngd) { int readfd; unsigned int readcount; int ret = DROPBEAR_FAILURE; + if (prngd) { #if DROPBEAR_USE_PRNGD - if (prngd) - { readfd = connect_unix(filename); - } - else #endif - { + } else { readfd = open(filename, O_RDONLY); } @@ -75,58 +70,31 @@ } readcount = 0; - while (len == 0 || readcount < len) - { + while (wantlen == 0 || readcount < wantlen) { int readlen, wantread; unsigned char readbuf[4096]; - if (!already_blocked && !prngd) - { - int res; - struct timeval timeout; - fd_set read_fds; - - timeout.tv_sec = 2; - timeout.tv_usec = 0; - - DROPBEAR_FD_ZERO(&read_fds); - FD_SET(readfd, &read_fds); - res = select(readfd + 1, &read_fds, NULL, NULL, &timeout); - if (res == 0) - { - dropbear_log(LOG_WARNING, "Warning: Reading the randomness source '%s' seems to have blocked.\nYou may need to find a better entropy source.", filename); - already_blocked = 1; - } - } - - if (len == 0) - { + if (wantlen == 0) { wantread = sizeof(readbuf); - } - else - { - wantread = MIN(sizeof(readbuf), len-readcount); + } else { + wantread = MIN(sizeof(readbuf), wantlen-readcount); } #if DROPBEAR_USE_PRNGD - if (prngd) - { + if (prngd) { char egdcmd[2]; egdcmd[0] = 0x02; /* blocking read */ egdcmd[1] = (unsigned char)wantread; - if (write(readfd, egdcmd, 2) < 0) - { + if (write(readfd, egdcmd, 2) < 0) { dropbear_exit("Can't send command to egd"); } } #endif - readlen = read(readfd, readbuf, wantread); if (readlen <= 0) { if (readlen < 0 && errno == EINTR) { continue; } - if (readlen == 0 && len == 0) - { + if (readlen == 0 && wantlen == 0) { /* whole file was read as requested */ break; } @@ -193,6 +161,63 @@ } #endif + +#ifdef HAVE_GETRANDOM +/* Reads entropy seed with getrandom(). + * May block if the kernel isn't ready. + * Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ +static int process_getrandom(hash_state *hs) { + char buf[INIT_SEED_SIZE]; + ssize_t ret; + + /* First try non-blocking so that we can warn about waiting */ + ret = getrandom(buf, sizeof(buf), GRND_NONBLOCK); + if (ret == -1) { + if (errno == ENOSYS) { + /* Old kernel */ + return DROPBEAR_FAILURE; + } + /* Other errors fall through to blocking getrandom() */ + TRACE(("first getrandom() failed: %d %s", errno, strerror(errno))) + if (errno == EAGAIN) { + dropbear_log(LOG_WARNING, "Waiting for kernel randomness to be initialised..."); + } + } + + /* Wait blocking if needed. Loop in case we get EINTR */ + while (ret != sizeof(buf)) { + ret = getrandom(buf, sizeof(buf), 0); + + if (ret == sizeof(buf)) { + /* Success */ + break; + } + if (ret == -1 && errno == EINTR) { + /* Try again. */ + continue; + } + if (ret >= 0) { + TRACE(("Short read %zd from getrandom() shouldn't happen", ret)) + /* Try again? */ + continue; + } + + /* Unexpected problem, fall back to /dev/urandom */ + TRACE(("2nd getrandom() failed: %d %s", errno, strerror(errno))) + break; + } + + if (ret == sizeof(buf)) { + /* Success, stir in the entropy */ + sha1_process(hs, (void*)buf, sizeof(buf)); + return DROPBEAR_SUCCESS; + } + + return DROPBEAR_FAILURE; + +} +#endif /* HAVE_GETRANDOM */ + /* Initialise the prng from /dev/urandom or prngd. This function can * be called multiple times */ void seedrandom() { @@ -202,6 +227,7 @@ pid_t pid; struct timeval tv; clock_t clockval; + int urandom_seeded = 0; #if DROPBEAR_FUZZ if (fuzz.fuzzing) { @@ -215,21 +241,31 @@ /* existing state */ sha1_process(&hs, (void*)hashpool, sizeof(hashpool)); -#if DROPBEAR_USE_PRNGD - if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1) - != DROPBEAR_SUCCESS) { - dropbear_exit("Failure reading random device %s", - DROPBEAR_PRNGD_SOCKET); - } -#else - /* non-blocking random source (probably /dev/urandom) */ - if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0) - != DROPBEAR_SUCCESS) { - dropbear_exit("Failure reading random device %s", - DROPBEAR_URANDOM_DEV); +#ifdef HAVE_GETRANDOM + if (process_getrandom(&hs) == DROPBEAR_SUCCESS) { + urandom_seeded = 1; } #endif + if (!urandom_seeded) { +#if DROPBEAR_USE_PRNGD + if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1) + != DROPBEAR_SUCCESS) { + dropbear_exit("Failure reading random device %s", + DROPBEAR_PRNGD_SOCKET); + urandom_seeded = 1; + } +#else + /* non-blocking random source (probably /dev/urandom) */ + if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0) + != DROPBEAR_SUCCESS) { + dropbear_exit("Failure reading random device %s", + DROPBEAR_URANDOM_DEV); + urandom_seeded = 1; + } +#endif + } /* urandom_seeded */ + /* A few other sources to fall back on. * Add more here for other platforms */ #ifdef __linux__ diff -r 789466c5956b -r f966834f0f9c includes.h --- a/includes.h Thu May 28 22:02:33 2020 +0800 +++ b/includes.h Thu May 28 22:50:41 2020 +0800 @@ -124,6 +124,10 @@ #include #endif +#ifdef HAVE_SYS_RANDOM_H +#include +#endif + #ifdef BUNDLED_LIBTOM #include "libtomcrypt/src/headers/tomcrypt.h" #include "libtommath/tommath.h"