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

Reply via email to