summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2020-05-28 22:50:41 +0800
committerMatt Johnston <matt@ucc.asn.au>2020-05-28 22:50:41 +0800
commit53ba0b4848196bbd7bb29812ee1cad855fea8f7f (patch)
tree38dd64b5ef3a75a001a565c069158dca71f677c1
parent7a23e540a450dd96e4abacb3893a3f3ef9d87ddb (diff)
downloaddropbear-53ba0b4848196bbd7bb29812ee1cad855fea8f7f.tar.gz
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.
-rw-r--r--configure.ac5
-rw-r--r--dbrandom.c144
-rw-r--r--includes.h4
3 files changed, 97 insertions, 56 deletions
diff --git a/configure.ac b/configure.ac
index bcb6e4a..848c261 100644
--- a/configure.ac
+++ b/configure.ac
@@ -370,7 +370,8 @@ AC_CHECK_HEADERS([netinet/in.h netinet/tcp.h \
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_FUNCS(clock_gettime)
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 --git a/dbrandom.c b/dbrandom.c
index 0a55bc5..8ea61f6 100644
--- a/dbrandom.c
+++ b/dbrandom.c
@@ -49,24 +49,19 @@ static int donerandinit = 0;
*
*/
-/* 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 @@ process_file(hash_state *hs, const char *filename,
}
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 @@ void fuzz_seed(void) {
}
#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 @@ void seedrandom() {
pid_t pid;
struct timeval tv;
clock_t clockval;
+ int urandom_seeded = 0;
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
@@ -215,20 +241,30 @@ void seedrandom() {
/* 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);
+#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);
- }
+ /* 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 */
diff --git a/includes.h b/includes.h
index 6432d6e..e8c3e18 100644
--- a/includes.h
+++ b/includes.h
@@ -124,6 +124,10 @@
#include <sys/uio.h>
#endif
+#ifdef HAVE_SYS_RANDOM_H
+#include <sys/random.h>
+#endif
+
#ifdef BUNDLED_LIBTOM
#include "libtomcrypt/src/headers/tomcrypt.h"
#include "libtommath/tommath.h"