Source-Changes-HG archive

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

[src/netbsd-6]: src Pull up following revision(s) (requested by tls in ticket...



details:   https://anonhg.NetBSD.org/src/rev/2a44af0513f3
branches:  netbsd-6
changeset: 774022:2a44af0513f3
user:      riz <riz%NetBSD.org@localhost>
date:      Fri Apr 20 23:35:20 2012 +0000

description:
Pull up following revision(s) (requested by tls in ticket #190):
        sys/sys/rnd.h: revision 1.31
        sys/sys/rnd.h: revision 1.32
        sys/sys/cprng.h: revision 1.5
        sys/kern/subr_cprng.c: revision 1.8
        share/man/man4/rnd.4: revision 1.19
        sys/kern/kern_rndq.c: revision 1.3
        sys/dev/rndpseudo.c: revision 1.8
        sys/dev/rndpseudo.c: revision 1.9
        sys/kern/kern_rndpool.c: revision 1.2
Address multiple problems with rnd(4)/cprng(9):
1) Add a per-cpu CPRNG to handle short reads from /dev/urandom so that
   programs like perl don't drain the entropy pool dry by repeatedly
   opening, reading 4 bytes, closing.
2) Really fix the locking around reseeds and destroys.
3) Fix the opportunistic-reseed strategy so it actually works, reseeding
   existing RNGs once each (as they are used, so idle RNGs don't get
   reseeded) until the pool is half empty or newly full again.
Fix a bug and a compilation problem.  Bug: spin mutexes don't have owners,
so KASSERT(!mutex_owned()) shouldn't be used to assert that the current
LWP does not have the mutex.  Compilation problem: explicitly include
sys/mutex.h from rnd.h so evbarm builds again.

diffstat:

 share/man/man4/rnd.4    |   37 ++++++++++++++++-
 sys/dev/rndpseudo.c     |   50 +++++++++++++++++++----
 sys/kern/kern_rndpool.c |   12 +++-
 sys/kern/kern_rndq.c    |   26 ++++++++---
 sys/kern/subr_cprng.c   |  102 +++++++++++++++++++++++++++++++++--------------
 sys/sys/cprng.h         |    4 +-
 sys/sys/rnd.h           |   11 ++++-
 7 files changed, 187 insertions(+), 55 deletions(-)

diffs (truncated from 550 to 300 lines):

diff -r 2312ff81a2d4 -r 2a44af0513f3 share/man/man4/rnd.4
--- a/share/man/man4/rnd.4      Fri Apr 20 23:32:14 2012 +0000
+++ b/share/man/man4/rnd.4      Fri Apr 20 23:35:20 2012 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: rnd.4,v 1.18 2011/12/17 21:21:59 wiz Exp $
+.\"    $NetBSD: rnd.4,v 1.18.2.1 2012/04/20 23:35:20 riz Exp $
 .\"
 .\" Copyright (c) 1997 Michael Graff
 .\" All rights reserved.
@@ -52,13 +52,32 @@
 the pseudo-device is read.
 .Pp
 The pseudodevice is cloning, which means that each time it is opened,
-a new instance of the stream generator is created.
+a new instance of the stream generator may be created.
 Interposing a stream
 generator between the entropy pool and readers in this manner protects
 readers from each other (each reader's random stream is generated from a
 unique key) and protects all users of the entropy pool from any attack
 which might correlate its successive outputs to each other, such as
 iterative guessing attacks.
+.Pp
+Certain programs make very short reads from
+.Pa /dev/urandom
+each time they begin execution.  One program with this behavior is
+.Xr perl 1 .
+If such a program is run repeatedly (for example from a network
+service or shell script), the resulting repeated keying of the stream
+generator can quickly drain the entropy pool dry.  As an optimization
+for such cases, a separate per-CPU instance of the stream generator
+is used to handle reads from
+.Pa /dev/urandom
+which are smaller than the key length of the underlying cipher.  Any
+read of a larger size causes an immediate allocation of a private
+instance of the stream generator for the reader.  Since all stream
+generators are automatically rekeyed upon use when sufficient entropy
+is available, the shared short-request generators do still offer
+some protection against other consumers of
+.Pa /dev/urandom ,
+though less than is provided for consumers making larger requests.
 .Sh USER ACCESS
 User code can obtain random values from the kernel in two ways.
 .Pp
@@ -190,6 +209,20 @@
 The device is a terminal, mouse, or other user input device.
 .It Dv RND_TYPE_RNG
 The device is a random number generator.
+.It Dv RND_TYPE_SKEW
+The "device" is a measurement of the skew between two clocks, such as a
+periodic device interrupt and the system timecounter, a timecounter and
+an audio codec, or some other source of pairs of events where each
+member of each pair is derived from a different instance of some
+recurring physical process.
+.It Dv RND_TYPE_ENV
+The device is an environmental sensor such as a temperature sensor or
+a fan speed sensor.
+.It Dv RND_TYPE_VM
+The "device" consists of timings of virtual memory system events.
+.It Dv RND_TYPE_POWER
+The device is a sensor returning changes in the power state of the
+system, such as battery charge state or A/C adapter state.
 .El
 .Pp
 .Va flags
diff -r 2312ff81a2d4 -r 2a44af0513f3 sys/dev/rndpseudo.c
--- a/sys/dev/rndpseudo.c       Fri Apr 20 23:32:14 2012 +0000
+++ b/sys/dev/rndpseudo.c       Fri Apr 20 23:35:20 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: rndpseudo.c,v 1.6.2.1 2012/04/19 19:59:11 riz Exp $    */
+/*     $NetBSD: rndpseudo.c,v 1.6.2.2 2012/04/20 23:35:20 riz Exp $    */
 
 /*-
  * Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rndpseudo.c,v 1.6.2.1 2012/04/19 19:59:11 riz Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rndpseudo.c,v 1.6.2.2 2012/04/20 23:35:20 riz Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_compat_netbsd.h"
@@ -54,6 +54,7 @@
 #include <sys/pool.h>
 #include <sys/kauth.h>
 #include <sys/cprng.h>
+#include <sys/cpu.h>
 #include <sys/stat.h>
 
 #include <sys/rnd.h>
@@ -96,6 +97,11 @@
 static pool_cache_t rp_cpc;
 
 /*
+ * The per-CPU RNGs used for short requests
+ */
+cprng_strong_t **rp_cpurngs;
+
+/*
  * A context.  cprng plus a smidge.
  */
 typedef struct {
@@ -193,6 +199,9 @@
        mutex_spin_enter(&rndpool_mtx);
        rndpool_add_data(&rnd_pool, &c, sizeof(u_int32_t), 1);
        mutex_spin_exit(&rndpool_mtx);
+
+       rp_cpurngs = kmem_zalloc(maxcpus * sizeof(cprng_strong_t *),
+                                KM_SLEEP);
 }
 
 int
@@ -251,8 +260,10 @@
          kauth_cred_t cred, int flags)
 {
        rp_ctx_t *ctx = fp->f_data;
+       cprng_strong_t *cprng;
        u_int8_t *bf;
        int strength, ret;
+       struct cpu_info *ci = curcpu();
 
        DPRINTF(RND_DEBUG_READ,
            ("Random:  Read of %zu requested, flags 0x%08x\n",
@@ -261,14 +272,33 @@
        if (uio->uio_resid == 0)
                return (0);
 
-       if (ctx->cprng == NULL) {
-               rnd_alloc_cprng(ctx);
-               if (__predict_false(ctx->cprng == NULL)) {
-                       return EIO;
+       if (ctx->hard || uio->uio_resid > NIST_BLOCK_KEYLEN_BYTES) {
+               if (ctx->cprng == NULL) {
+                       rnd_alloc_cprng(ctx);
                }
+               cprng = ctx->cprng;
+       } else {
+               int index = cpu_index(ci);
+
+               if (__predict_false(rp_cpurngs[index] == NULL)) {
+                       char rngname[32];
+
+                       snprintf(rngname, sizeof(rngname),
+                                "%s-short", cpu_name(ci));
+                       rp_cpurngs[index] =
+                           cprng_strong_create(rngname, IPL_NONE,
+                                               CPRNG_INIT_ANY |
+                                               CPRNG_REKEY_ANY);
+               }
+               cprng = rp_cpurngs[index];
+       }
+
+       if (__predict_false(cprng == NULL)) {
+               printf("NULL rng!\n");
+               return EIO;
         }
 
-       strength = cprng_strong_strength(ctx->cprng);
+       strength = cprng_strong_strength(cprng);
        ret = 0;
        bf = pool_cache_get(rp_pc, PR_WAITOK);
        while (uio->uio_resid > 0) {
@@ -284,7 +314,7 @@
                        n = want;
                }
 
-               nread = cprng_strong(ctx->cprng, bf, n,
+               nread = cprng_strong(cprng, bf, n,
                                     (fp->f_flag & FNONBLOCK) ? FNONBLOCK : 0);
                if (nread != n) {
                        if (fp->f_flag & FNONBLOCK) {
@@ -294,6 +324,7 @@
                        }
                        goto out;
                }
+
                ret = uiomove((void *)bf, nread, uio);
                if (ret != 0 || n < want) {
                        goto out;
@@ -302,9 +333,10 @@
 out:
        if (ctx->bytesonkey >= strength) {
                /* Force reseed of underlying DRBG (prediction resistance) */
-               cprng_strong_deplete(ctx->cprng);
+               cprng_strong_deplete(cprng);
                ctx->bytesonkey = 0;
        }
+
        pool_cache_put(rp_pc, bf);
        return (ret);
 }
diff -r 2312ff81a2d4 -r 2a44af0513f3 sys/kern/kern_rndpool.c
--- a/sys/kern/kern_rndpool.c   Fri Apr 20 23:32:14 2012 +0000
+++ b/sys/kern/kern_rndpool.c   Fri Apr 20 23:35:20 2012 +0000
@@ -1,4 +1,4 @@
-/*      $NetBSD: kern_rndpool.c,v 1.1 2012/02/02 19:43:07 tls Exp $        */
+/*      $NetBSD: kern_rndpool.c,v 1.1.2.1 2012/04/20 23:35:20 riz Exp $        */
 
 /*-
  * Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_rndpool.c,v 1.1 2012/02/02 19:43:07 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_rndpool.c,v 1.1.2.1 2012/04/20 23:35:20 riz Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -52,7 +52,8 @@
 /*
  * Let others know: the pool is full.
  */
-int rnd_full;
+int rnd_full = 0;                      /* Flag: is the pool full? */
+int rnd_filled = 0;                    /* Count: how many times filled? */
 
 static inline void rndpool_add_one_word(rndpool_t *, u_int32_t);
 
@@ -216,6 +217,7 @@
        if (rp->stats.curentropy > RND_POOLBITS) {
                rp->stats.discarded += (rp->stats.curentropy - RND_POOLBITS);
                rp->stats.curentropy = RND_POOLBITS;
+               rnd_filled++;
                rnd_full = 1;
        }
 }
@@ -246,7 +248,9 @@
        buf = p;
        remain = len;
 
-       rnd_full = 0;
+       if (rp->stats.curentropy < RND_POOLBITS / 2) {
+               rnd_full = 0;
+       }
 
        if (mode == RND_EXTRACT_ANY)
                good = 1;
diff -r 2312ff81a2d4 -r 2a44af0513f3 sys/kern/kern_rndq.c
--- a/sys/kern/kern_rndq.c      Fri Apr 20 23:32:14 2012 +0000
+++ b/sys/kern/kern_rndq.c      Fri Apr 20 23:35:20 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_rndq.c,v 1.1.2.1 2012/04/19 19:59:10 riz Exp $    */
+/*     $NetBSD: kern_rndq.c,v 1.1.2.2 2012/04/20 23:35:20 riz Exp $    */
 
 /*-
  * Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_rndq.c,v 1.1.2.1 2012/04/19 19:59:10 riz Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_rndq.c,v 1.1.2.2 2012/04/20 23:35:20 riz Exp $");
 
 #include <sys/param.h>
 #include <sys/ioctl.h>
@@ -221,6 +221,16 @@
         */
        mutex_spin_enter(&rndsink_mtx);
        TAILQ_FOREACH_SAFE(sink, &rnd_sinks, tailq, tsink) {
+               if (!mutex_tryenter(&sink->mtx)) {
+#ifdef RND_VERBOSE
+                       printf("rnd_wakeup_readers: "
+                              "skipping busy rndsink\n");
+#endif
+                       continue;
+               }
+
+               KASSERT(RSTATE_PENDING == sink->state);
+               
                if ((sink->len + RND_ENTROPY_THRESHOLD) * 8 <
                        rndpool_get_entropy_count(&rnd_pool)) {
                        /* We have enough entropy to sink some here. */
@@ -230,13 +240,12 @@
                                panic("could not extract estimated "
                                      "entropy from pool");
                        }
-                       /* Skip if busy, else mark in-progress */
-                       if (!mutex_tryenter(&sink->mtx)) {
-                           continue;
-                       }
+                       sink->state = RSTATE_HASBITS;
                        /* Move this sink to the list of pending callbacks */
                        TAILQ_REMOVE(&rnd_sinks, sink, tailq);
                        TAILQ_INSERT_HEAD(&sunk, sink, tailq);
+               } else {
+                       mutex_exit(&sink->mtx);
                }
        }
        mutex_spin_exit(&rndsink_mtx);
@@ -269,6 +278,7 @@
                       " (cb %p, arg %p).\n",
                       (int)sink->len, sink->name, sink->cb, sink->arg);
 #endif
+               sink->state = RSTATE_HASBITS;
                sink->cb(sink->arg);
                TAILQ_REMOVE(&sunk, sink, tailq);
                mutex_spin_exit(&sink->mtx);
@@ -976,16 +986,19 @@
 #endif



Home | Main Index | Thread Index | Old Index