Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/lib/libc/gen Re-stir after forking, fixes PR lib/25367.



details:   https://anonhg.NetBSD.org/src/rev/c80ab694fadb
branches:  trunk
changeset: 329766:c80ab694fadb
user:      roy <roy%NetBSD.org@localhost>
date:      Sat Jun 07 20:55:47 2014 +0000

description:
Re-stir after forking, fixes PR lib/25367.
Re-stir after consuming 1600000 bytes, fixes PR lib/45952.

diffstat:

 lib/libc/gen/arc4random.c |  95 ++++++++++++++++++++++++++++++++++------------
 1 files changed, 69 insertions(+), 26 deletions(-)

diffs (212 lines):

diff -r 142065f0a700 -r c80ab694fadb lib/libc/gen/arc4random.c
--- a/lib/libc/gen/arc4random.c Sat Jun 07 18:59:16 2014 +0000
+++ b/lib/libc/gen/arc4random.c Sat Jun 07 20:55:47 2014 +0000
@@ -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 @@
 #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 @@
 #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 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 @@
        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 @@
         * 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 @@
 static inline uint8_t
 arc4_getbyte(struct arc4_stream *as)
 {
+
        return arc4_getbyte_ij(as, &as->i, &as->j);
 }
 
@@ -176,6 +216,7 @@
 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 @@
 void
 arc4random_stir(void)
 {
+
        LOCK(&rs);
        arc4_stir(&rs);
        UNLOCK(&rs);
@@ -194,8 +236,9 @@
 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 @@
        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 @@
        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 @@
        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



Home | Main Index | Thread Index | Old Index