Source-Changes-HG archive

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

[src/trunk]: src/lib/libc/gen Make arc4random far less greedy for entropy. M...



details:   https://anonhg.NetBSD.org/src/rev/e300b1212c3d
branches:  trunk
changeset: 777638:e300b1212c3d
user:      tls <tls%NetBSD.org@localhost>
date:      Mon Feb 27 04:25:12 2012 +0000

description:
Make arc4random far less greedy for entropy.  Make arc4random actually
implement arc4 when used by threaded programs.

diffstat:

 lib/libc/gen/arc4random.c |  174 ++++++++++++++++++++++++++++-----------------
 1 files changed, 109 insertions(+), 65 deletions(-)

diffs (265 lines):

diff -r 2253d9a5fe9b -r e300b1212c3d lib/libc/gen/arc4random.c
--- a/lib/libc/gen/arc4random.c Mon Feb 27 01:39:58 2012 +0000
+++ b/lib/libc/gen/arc4random.c Mon Feb 27 04:25:12 2012 +0000
@@ -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 @@
 #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 @@
 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);
+       /*
+        * 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();
        }
-#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;
-               }
-       }
-#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 @@
        return val;
 }
 
-void
-arc4random_stir(void)
+static inline void
+_arc4random_stir_unlocked(void)
 {
        if (!rs_initialized) {
                arc4_init(&rs);
@@ -171,23 +163,67 @@
 }
 
 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);
 }
 
+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)
+               arc4_stir(&rs);
+       return arc4_getword(&rs);
+}
+
 uint32_t
 arc4random(void)
 {
-       if (!rs_initialized)
-               arc4random_stir();
-       return arc4_getword(&rs);
+       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;
 }
 
-void
-arc4random_buf(void *buf, size_t len)
+static void
+_arc4random_buf_unlocked(void *buf, size_t len)
 {
        uint8_t *bp = buf;
        uint8_t *ep = bp + len;
@@ -200,6 +236,20 @@
                *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 @@
  * [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 @@
         * 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 @@
        return r % upper_bound;
 }
 
-
-#if 0
-/*-------- Test code for i386 --------*/
-#include <stdio.h>
-#include <machine/pctr.h>
-int
-main(int argc, char **argv)
+uint32_t
+arc4random_uniform(uint32_t upper_bound)
 {
-       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 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;
 }
-#endif



Home | Main Index | Thread Index | Old Index