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; +}