Index: arc4random.c =================================================================== RCS file: /cvsroot/src/lib/libc/gen/arc4random.c,v retrieving revision 1.24 diff -u -p -u -r1.24 arc4random.c --- arc4random.c 12 Jun 2014 19:12:19 -0000 1.24 +++ arc4random.c 18 Jul 2014 14:33:22 -0000 @@ -36,10 +36,12 @@ __RCSID("$NetBSD: arc4random.c,v 1.24 20 #include #include #include +#include #include #include #include #include +#include #include #ifdef __weak_alias @@ -63,13 +65,14 @@ struct arc4_stream { #ifdef _REENTRANT #define LOCK(rs) do { \ + arc4_check_init(&rs); \ if (__isthreaded) mutex_lock(&(rs)->mtx); \ } while (/*CONSTCOND*/ 0) #define UNLOCK(rs) do { \ if (__isthreaded) mutex_unlock(&(rs)->mtx); \ } while (/*CONSTCOND*/ 0) #else -#define LOCK(rs) +#define LOCK(rs) arc4_check_init(&rs) #define UNLOCK(rs) #endif @@ -79,9 +82,10 @@ struct arc4_stream { #define S64(n) S16(n), S16(n + 16), S16(n + 32), S16(n + 48) #define S256 S64(0), S64(64), S64(128), S64(192) -static struct arc4_stream rs = { .inited = false, - .i = 0xff, .j = 0, .s = { S256 }, - .count = 0, .mtx = MUTEX_INITIALIZER }; +static const struct arc4_stream proto = { .inited = true, .i = 0xff, .j = 0, + .s = { S256 }, .count = 0, .mtx = MUTEX_INITIALIZER }; + +static struct arc4_stream *rs; #undef S #undef S4 @@ -94,43 +98,28 @@ static __noinline void arc4_stir(struct static inline uint8_t arc4_getbyte(struct arc4_stream *); static inline uint32_t arc4_getword(struct arc4_stream *); -#ifdef _REENTRANT -static void -arc4_fork_prepare(void) -{ - - LOCK(&rs); -} - -static void -arc4_fork_parent(void) -{ - - UNLOCK(&rs); -} -#else -#define arc4_fork_prepare NULL -#define arc4_fork_parent NULL -#endif - static void -arc4_fork_child(void) +arc4_init(struct arc4_stream **rsp) { - - /* Reset the counter to a force new stir after forking */ - rs.count = 0; - UNLOCK(&rs); + size_t page = (size_t)sysconf(_SC_PAGESIZE); + struct arc4_stream *as = mmap(NULL, page, PROT_READ|PROT_WRITE, + MAP_ANON, -1, 0); + if (as == MAP_FAILED || minherit(as, page, MAP_INHERIT_ZERO) == -1) + abort(); + memcpy(as, &proto, sizeof(proto)); + *rsp = as; } static inline void -arc4_check_init(struct arc4_stream *as) +arc4_check_init(struct arc4_stream **rsp) { - - if (__predict_false(!as->inited)) { - as->inited = true; - pthread_atfork(arc4_fork_prepare, - arc4_fork_parent, arc4_fork_child); + if (__predict_false(*rsp == NULL)) { + arc4_init(rsp); + return; } + + if (__predict_false(!(*rsp)->inited)) + memcpy(*rsp, &proto, sizeof(proto)); } static inline void @@ -156,8 +145,6 @@ arc4_stir(struct arc4_stream *as) size_t len; size_t i, j; - arc4_check_init(as); - /* * This code once opened and read /dev/urandom on each * call. That causes repeated rekeying of the kernel stream @@ -234,19 +221,19 @@ void arc4random_stir(void) { - LOCK(&rs); - arc4_stir(&rs); - UNLOCK(&rs); + LOCK(rs); + arc4_stir(rs); + UNLOCK(rs); } void arc4random_addrandom(u_char *dat, int datlen) { - LOCK(&rs); - arc4_stir_if_needed(&rs, datlen); - arc4_addrandom(&rs, dat, datlen); - UNLOCK(&rs); + LOCK(rs); + arc4_stir_if_needed(rs, datlen); + arc4_addrandom(rs, dat, datlen); + UNLOCK(rs); } uint32_t @@ -254,10 +241,10 @@ arc4random(void) { uint32_t v; - LOCK(&rs); - arc4_stir_if_needed(&rs, sizeof(v)); - v = arc4_getword(&rs); - UNLOCK(&rs); + LOCK(rs); + arc4_stir_if_needed(rs, sizeof(v)); + v = arc4_getword(rs); + UNLOCK(rs); return v; } @@ -268,19 +255,19 @@ arc4random_buf(void *buf, size_t len) uint8_t *ep = bp + len; uint8_t i, j; - LOCK(&rs); - arc4_stir_if_needed(&rs, len); + LOCK(rs); + arc4_stir_if_needed(rs, len); /* cache i and j - compiler can't know 'buf' doesn't alias them */ - i = rs.i; - j = rs.j; + i = rs->i; + j = rs->j; while (bp < ep) - *bp++ = arc4_getbyte_ij(&rs, &i, &j); - rs.i = i; - rs.j = j; + *bp++ = arc4_getbyte_ij(rs, &i, &j); + rs->i = i; + rs->j = j; - UNLOCK(&rs); + UNLOCK(rs); } /*- @@ -311,8 +298,8 @@ arc4random_uniform(uint32_t upper_bound) /* ((2^32 - x) % x) == (2^32 % x) when x <= 2^31 */ min = (0xFFFFFFFFU - upper_bound + 1) % upper_bound; - LOCK(&rs); - arc4_stir_if_needed(&rs, sizeof(r)); + LOCK(rs); + arc4_stir_if_needed(rs, sizeof(r)); /* * This could theoretically loop forever but each retry has @@ -321,9 +308,9 @@ arc4random_uniform(uint32_t upper_bound) * to re-roll (at all). */ do - r = arc4_getword(&rs); + r = arc4_getword(rs); while (r < min); - UNLOCK(&rs); + UNLOCK(rs); return r % upper_bound; }