Module Name:    src
Committed By:   tls
Date:           Mon Feb 27 04:25:12 UTC 2012

Modified Files:
        src/lib/libc/gen: arc4random.c

Log Message:
Make arc4random far less greedy for entropy.  Make arc4random actually
implement arc4 when used by threaded programs.


To generate a diff of this commit:
cvs rdiff -u -r1.10 -r1.11 src/lib/libc/gen/arc4random.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libc/gen/arc4random.c
diff -u src/lib/libc/gen/arc4random.c:1.10 src/lib/libc/gen/arc4random.c:1.11
--- src/lib/libc/gen/arc4random.c:1.10	Fri Feb  4 22:07:07 2011
+++ src/lib/libc/gen/arc4random.c	Mon Feb 27 04:25:12 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: arc4random.c,v 1.10 2011/02/04 22:07:07 christos Exp $	*/
+/*	$NetBSD: arc4random.c,v 1.11 2012/02/27 04:25:12 tls Exp $	*/
 /*	$OpenBSD: arc4random.c,v 1.6 2001/06/05 05:05:38 pvalchev Exp $	*/
 
 /*
@@ -27,10 +27,11 @@
 
 #include <sys/cdefs.h>
 #if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: arc4random.c,v 1.10 2011/02/04 22:07:07 christos Exp $");
+__RCSID("$NetBSD: arc4random.c,v 1.11 2012/02/27 04:25:12 tls Exp $");
 #endif /* LIBC_SCCS and not lint */
 
 #include "namespace.h"
+#include "reentrant.h"
 #include <fcntl.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -44,13 +45,15 @@ __weak_alias(arc4random,_arc4random)
 #endif
 
 struct arc4_stream {
+	mutex_t mtx;
 	uint8_t i;
 	uint8_t j;
 	uint8_t s[256];
 };
 
 static int rs_initialized;
-static struct arc4_stream rs;
+/* XXX lint explodes with an internal error if only mtx is initialized! */
+static struct arc4_stream rs = { .i = 0, .mtx = MUTEX_INITIALIZER };
 
 static inline void arc4_init(struct arc4_stream *);
 static inline void arc4_addrandom(struct arc4_stream *, u_char *, int);
@@ -89,40 +92,29 @@ arc4_addrandom(struct arc4_stream *as, u
 static void
 arc4_stir(struct arc4_stream *as)
 {
-	int     fd;
-	struct {
-		struct timeval tv;
-		u_int rnd[(128 - sizeof(struct timeval)) / sizeof(u_int)];
-	}       rdat;
+	int rdat[128 / sizeof(int)];
 	int	n;
+	int mib[2];
+	unsigned int i;
+	size_t len;
 
-	gettimeofday(&rdat.tv, NULL);
-	fd = open("/dev/urandom", O_RDONLY);
-	if (fd != -1) {
-		read(fd, rdat.rnd, sizeof(rdat.rnd));
-		close(fd);
-	}
-#ifdef KERN_URND
-	else {
-		int mib[2];
-		u_int i;
-		size_t len;
-
-		/* Device could not be opened, we might be chrooted, take
-		 * randomness from sysctl. */
-
-		mib[0] = CTL_KERN;
-		mib[1] = KERN_URND;
-
-		for (i = 0; i < sizeof(rdat.rnd) / sizeof(u_int); i++) {
-			len = sizeof(u_int);
-			if (sysctl(mib, 2, &rdat.rnd[i], &len, NULL, 0) == -1)
-				break;
-		}
+	/*
+	 * This code once opened and read /dev/urandom on each
+	 * call.  That causes repeated rekeying of the kernel stream
+	 * generator, which is very wasteful.  Because of application
+	 * behavior, caching the fd doesn't really help.  So we just
+	 * fill up the tank from sysctl, which is a tiny bit slower
+	 * for us but much friendlier to other entropy consumers.
+	 */
+
+	mib[0] = CTL_KERN;
+	mib[1] = KERN_URND;
+
+	for (i = 0; i < sizeof(rdat) / sizeof(int); i++) {
+		len = sizeof(rdat[i]);
+		if (sysctl(mib, 2, &rdat[i], &len, NULL, 0) == -1)
+			abort();
 	}
-#endif
-	/* fd < 0 or failed sysctl ?  Ah, what the heck. We'll just take
-	 * whatever was on the stack... */
 
 	arc4_addrandom(as, (void *) &rdat, sizeof(rdat));
 
@@ -160,8 +152,8 @@ arc4_getword(struct arc4_stream *as)
 	return val;
 }
 
-void
-arc4random_stir(void)
+static inline void
+_arc4random_stir_unlocked(void)
 {
 	if (!rs_initialized) {
 		arc4_init(&rs);
@@ -171,23 +163,67 @@ arc4random_stir(void)
 }
 
 void
-arc4random_addrandom(u_char *dat, int datlen)
+arc4random_stir(void)
+{
+#ifdef _REENTRANT
+	if (__isthreaded) {
+		mutex_lock(&rs.mtx);
+                _arc4random_stir_unlocked();
+		mutex_unlock(&rs.mtx);
+		return;
+        }
+#endif
+	_arc4random_stir_unlocked();
+}
+
+static inline void
+_arc4random_addrandom_unlocked(u_char *dat, int datlen)
 {
 	if (!rs_initialized)
-		arc4random_stir();
+		arc4_stir(&rs);
 	arc4_addrandom(&rs, dat, datlen);
 }
 
-uint32_t
-arc4random(void)
+void
+arc4random_addrandom(u_char *dat, int datlen)
+{
+#ifdef _REENTRANT
+	if (__isthreaded) {
+		mutex_lock(&rs.mtx);
+		_arc4random_addrandom_unlocked(dat, datlen);
+		mutex_unlock(&rs.mtx);
+		return;
+	}
+#endif
+	_arc4random_addrandom_unlocked(dat, datlen);
+}
+
+static inline uint32_t
+_arc4random_unlocked(void)
 {
 	if (!rs_initialized)
-		arc4random_stir();
+		arc4_stir(&rs);
 	return arc4_getword(&rs);
 }
 
-void
-arc4random_buf(void *buf, size_t len)
+uint32_t
+arc4random(void)
+{
+	uint32_t v;
+#ifdef _REENTRANT
+	if (__isthreaded) {
+		mutex_lock(&rs.mtx);
+		v = _arc4random_unlocked();
+		mutex_unlock(&rs.mtx);
+		return v;
+	}
+#endif
+	v = _arc4random_unlocked();
+	return v;
+}
+
+static void
+_arc4random_buf_unlocked(void *buf, size_t len)
 {
 	uint8_t *bp = buf;
 	uint8_t *ep = bp + len;
@@ -200,6 +236,20 @@ arc4random_buf(void *buf, size_t len)
 		*bp++ = arc4_getbyte(&rs);
 }
 
+void
+arc4random_buf(void *buf, size_t len)
+{
+#ifdef _REENTRANT
+	if (__isthreaded) {
+		mutex_lock(&rs.mtx);
+		_arc4random_buf_unlocked(buf, len);
+		mutex_unlock(&rs.mtx);
+		return;
+	} else
+#endif
+	_arc4random_buf_unlocked(buf, len);
+}
+
 /*-
  * Written by Damien Miller.
  * With simplifications by Jinmei Tatuya.
@@ -216,8 +266,8 @@ arc4random_buf(void *buf, size_t len)
  * [2^32 % upper_bound, 2^32[ which maps back to
  * [0, upper_bound[ after reduction modulo upper_bound.
  */
-uint32_t
-arc4random_uniform(uint32_t upper_bound)
+static uint32_t
+_arc4random_uniform_unlocked(uint32_t upper_bound)
 {
 	uint32_t r, min;
 
@@ -243,7 +293,7 @@ arc4random_uniform(uint32_t upper_bound)
 	 * to re-roll (at all).
 	 */
 	if (!rs_initialized)
-		arc4random_stir();
+		arc4_stir(&rs);
 	if (arc4_getbyte(&rs) & 1)
 		(void)arc4_getbyte(&rs);
 	do
@@ -253,24 +303,18 @@ arc4random_uniform(uint32_t upper_bound)
 	return r % upper_bound;
 }
 
-
-#if 0
-/*-------- Test code for i386 --------*/
-#include <stdio.h>
-#include <machine/pctr.h>
-int
-main(int argc, char **argv)
-{
-	const int iter = 1000000;
-	int     i;
-	pctrval v;
-
-	v = rdtsc();
-	for (i = 0; i < iter; i++)
-		arc4random();
-	v = rdtsc() - v;
-	v /= iter;
-
-	printf("%qd cycles\n", v);
-}
+uint32_t
+arc4random_uniform(uint32_t upper_bound)
+{
+	uint32_t v;
+#ifdef _REENTRANT
+	if (__isthreaded) {
+		mutex_lock(&rs.mtx);
+		v = _arc4random_uniform_unlocked(upper_bound);
+		mutex_unlock(&rs.mtx);
+		return v;
+	}
 #endif
+	v = _arc4random_uniform_unlocked(upper_bound);
+	return v;
+}

Reply via email to