Module Name: src Committed By: roy Date: Sat Jun 7 20:55:47 UTC 2014
Modified Files: src/lib/libc/gen: arc4random.c Log Message: Re-stir after forking, fixes PR lib/25367. Re-stir after consuming 1600000 bytes, fixes PR lib/45952. To generate a diff of this commit: cvs rdiff -u -r1.21 -r1.22 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.21 src/lib/libc/gen/arc4random.c:1.22 --- src/lib/libc/gen/arc4random.c:1.21 Thu Oct 17 23:56:17 2013 +++ src/lib/libc/gen/arc4random.c Sat Jun 7 20:55:47 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: arc4random.c,v 1.21 2013/10/17 23:56:17 christos Exp $ */ +/* $NetBSD: arc4random.c,v 1.22 2014/06/07 20:55:47 roy Exp $ */ /* $OpenBSD: arc4random.c,v 1.6 2001/06/05 05:05:38 pvalchev Exp $ */ /* @@ -27,12 +27,14 @@ #include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: arc4random.c,v 1.21 2013/10/17 23:56:17 christos Exp $"); +__RCSID("$NetBSD: arc4random.c,v 1.22 2014/06/07 20:55:47 roy Exp $"); #endif /* LIBC_SCCS and not lint */ #include "namespace.h" #include "reentrant.h" #include <fcntl.h> +#include <pthread.h> +#include <stdbool.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> @@ -49,25 +51,19 @@ __weak_alias(arc4random_uniform,_arc4ran #endif struct arc4_stream { - uint8_t stirred; - uint8_t pad; + bool inited; uint8_t i; uint8_t j; uint8_t s[(uint8_t)~0u + 1u]; /* 256 to you and me */ + size_t count; mutex_t mtx; }; #ifdef _REENTRANT -#define LOCK(rs) { \ - int isthreaded = __isthreaded; \ - if (isthreaded) \ - mutex_lock(&(rs)->mtx); -#define UNLOCK(rs) \ - if (isthreaded) \ - mutex_unlock(&(rs)->mtx); \ - } +#define LOCK(rs) if (__isthreaded) mutex_lock(&(rs)->mtx); +#define UNLOCK(rs) if (__isthreaded) mutex_unlock(&(rs)->mtx); #else -#define LOCK(rs) +#define LOCK(rs) #define UNLOCK(rs) #endif @@ -77,8 +73,9 @@ 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 = { .i = 0xff, .j = 0, .s = { S256 }, - .stirred = 0, .mtx = MUTEX_INITIALIZER }; +static struct arc4_stream rs = { .inited = false, + .i = 0xff, .j = 0, .s = { S256 }, + .count = 0, .mtx = MUTEX_INITIALIZER }; #undef S #undef S4 @@ -91,14 +88,43 @@ static __noinline void arc4_stir(struct static inline uint8_t arc4_getbyte(struct arc4_stream *); static inline uint32_t arc4_getword(struct arc4_stream *); -static inline int +#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) +{ + + /* Reset the counter to a force new stir after forking */ + rs.count = 0; + UNLOCK(&rs); +} + +static inline void arc4_check_init(struct arc4_stream *as) { - if (__predict_true(rs.stirred)) - return 0; - arc4_stir(as); - return 1; + if (__predict_false(!as->inited)) { + as->inited = true; + pthread_atfork(arc4_fork_prepare, + arc4_fork_parent, arc4_fork_child); + } } static inline void @@ -124,6 +150,8 @@ 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 @@ -146,10 +174,21 @@ arc4_stir(struct arc4_stream *as) * paper "Weaknesses in the Key Scheduling Algorithm of RC4" * by Fluher, Mantin, and Shamir. (N = 256 in our case.) */ - for (j = 0; j < __arraycount(as->s) * 4; j++) + for (j = 0; j < __arraycount(as->s) * sizeof(uint32_t); j++) arc4_getbyte(as); - as->stirred = 1; + /* Stir again after swallowing 1600000 bytes or if the pid changes */ + as->count = 1600000; +} + +static inline void +arc4_stir_if_needed(struct arc4_stream *as, size_t len) +{ + + if (__predict_false(as->count <= len)) + arc4_stir(as); + else + as->count -= len; } static __inline uint8_t @@ -169,6 +208,7 @@ arc4_getbyte_ij(struct arc4_stream *as, static inline uint8_t arc4_getbyte(struct arc4_stream *as) { + return arc4_getbyte_ij(as, &as->i, &as->j); } @@ -176,6 +216,7 @@ static inline uint32_t arc4_getword(struct arc4_stream *as) { uint32_t val; + val = arc4_getbyte(as) << 24; val |= arc4_getbyte(as) << 16; val |= arc4_getbyte(as) << 8; @@ -186,6 +227,7 @@ arc4_getword(struct arc4_stream *as) void arc4random_stir(void) { + LOCK(&rs); arc4_stir(&rs); UNLOCK(&rs); @@ -194,8 +236,9 @@ arc4random_stir(void) void arc4random_addrandom(u_char *dat, int datlen) { + LOCK(&rs); - arc4_check_init(&rs); + arc4_stir_if_needed(&rs, datlen); arc4_addrandom(&rs, dat, datlen); UNLOCK(&rs); } @@ -206,7 +249,7 @@ arc4random(void) uint32_t v; LOCK(&rs); - arc4_check_init(&rs); + arc4_stir_if_needed(&rs, sizeof(v)); v = arc4_getword(&rs); UNLOCK(&rs); return v; @@ -220,7 +263,7 @@ arc4random_buf(void *buf, size_t len) uint8_t i, j; LOCK(&rs); - arc4_check_init(&rs); + arc4_stir_if_needed(&rs, len); /* cache i and j - compiler can't know 'buf' doesn't alias them */ i = rs.i; @@ -263,7 +306,7 @@ arc4random_uniform(uint32_t upper_bound) min = (0xFFFFFFFFU - upper_bound + 1) % upper_bound; LOCK(&rs); - arc4_check_init(&rs); + arc4_stir_if_needed(&rs, sizeof(r)); /* * This could theoretically loop forever but each retry has