Module Name:    src
Committed By:   tls
Date:           Tue Apr 10 14:02:28 UTC 2012

Modified Files:
        src/sys/kern: kern_rndq.c subr_cprng.c
        src/sys/lib/libkern: arc4random.c
        src/sys/sys: rnd.h

Log Message:
Add a spin mutex to the rndsink structure; it is used to avoid lock
ordering and sleep-holding-locks problems when rekeying, and thus
to avoid a nasty race between cprng destruction and reseeding.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/sys/kern/kern_rndq.c
cvs rdiff -u -r1.5 -r1.6 src/sys/kern/subr_cprng.c
cvs rdiff -u -r1.31 -r1.32 src/sys/lib/libkern/arc4random.c
cvs rdiff -u -r1.29 -r1.30 src/sys/sys/rnd.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/kern_rndq.c
diff -u src/sys/kern/kern_rndq.c:1.1 src/sys/kern/kern_rndq.c:1.2
--- src/sys/kern/kern_rndq.c:1.1	Thu Feb  2 19:43:07 2012
+++ src/sys/kern/kern_rndq.c	Tue Apr 10 14:02:27 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_rndq.c,v 1.1 2012/02/02 19:43:07 tls Exp $	*/
+/*	$NetBSD: kern_rndq.c,v 1.2 2012/04/10 14:02:27 tls 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 2012/02/02 19:43:07 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_rndq.c,v 1.2 2012/04/10 14:02:27 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/ioctl.h>
@@ -109,13 +109,17 @@ volatile int			rnd_timeout_pending;
 SIMPLEQ_HEAD(, _rnd_sample_t)	rnd_samples;
 kmutex_t			rnd_mtx;
 
+
 /*
  * Entropy sinks: usually other generators waiting to be rekeyed.
  *
  * A sink's callback MUST NOT re-add the sink to the list, or
- * list corruption will occur.
+ * list corruption will occur.  The list is protected by the
+ * rndsink_mtx, which must be released before calling any sink's
+ * callback.
  */
 TAILQ_HEAD(, rndsink)		rnd_sinks;
+kmutex_t			rndsink_mtx;
 
 /*
  * Memory pool for sample buffers
@@ -215,6 +219,7 @@ rnd_wakeup_readers(void)
 	/*
 	 * First, take care of in-kernel consumers needing rekeying.
 	 */
+	mutex_spin_enter(&rndsink_mtx);
 	TAILQ_FOREACH_SAFE(sink, &rnd_sinks, tailq, tsink) {
 		if ((sink->len + RND_ENTROPY_THRESHOLD) * 8 <
 			rndpool_get_entropy_count(&rnd_pool)) {
@@ -225,11 +230,16 @@ rnd_wakeup_readers(void)
 				panic("could not extract estimated "
 				      "entropy from pool");
 			}
+			/* Skip if busy, else mark in-progress */
+			if (!mutex_tryenter(&sink->mtx)) {
+			    continue;
+			}
 			/* Move this sink to the list of pending callbacks */
 			TAILQ_REMOVE(&rnd_sinks, sink, tailq);
 			TAILQ_INSERT_HEAD(&sunk, sink, tailq);
 		}
 	}
+	mutex_spin_exit(&rndsink_mtx);
 		
 	/*
 	 * If we still have enough new bits to do something, feed userspace.
@@ -261,6 +271,7 @@ rnd_wakeup_readers(void)
 #endif
 		sink->cb(sink->arg);
 		TAILQ_REMOVE(&sunk, sink, tailq);
+		mutex_spin_exit(&sink->mtx);
 	}
 }
 
@@ -362,6 +373,7 @@ rnd_init(void)
 		return;
 
 	mutex_init(&rnd_mtx, MUTEX_DEFAULT, IPL_VM);
+	mutex_init(&rndsink_mtx, MUTEX_DEFAULT, IPL_VM);
 
 	callout_init(&rnd_callout, CALLOUT_MPSAFE);
 	callout_setfunc(&rnd_callout, rnd_timeout, NULL);
@@ -962,9 +974,12 @@ rndsink_attach(rndsink_t *rs)
 	printf("rnd: entropy sink \"%s\" wants %d bytes of data.\n",
 	       rs->name, (int)rs->len);
 #endif
-	mutex_spin_enter(&rndpool_mtx);
+
+	KASSERT(mutex_owned(&rs->mtx));
+
+	mutex_spin_enter(&rndsink_mtx);
 	TAILQ_INSERT_TAIL(&rnd_sinks, rs, tailq);
-	mutex_spin_exit(&rndpool_mtx);
+	mutex_spin_exit(&rndsink_mtx);
 	mutex_spin_enter(&rnd_mtx);
 	if (rnd_timeout_pending == 0) {
 		rnd_timeout_pending = 1;
@@ -980,13 +995,16 @@ rndsink_detach(rndsink_t *rs)
 #ifdef RND_VERBOSE
 	printf("rnd: entropy sink \"%s\" no longer wants data.\n", rs->name);
 #endif
-	mutex_spin_enter(&rndpool_mtx);
+
+	KASSERT(mutex_owned(&rs->mtx));
+
+	mutex_spin_enter(&rndsink_mtx);
 	TAILQ_FOREACH_SAFE(sink, &rnd_sinks, tailq, tsink) {
 		if (sink == rs) {
 			TAILQ_REMOVE(&rnd_sinks, rs, tailq);
 		}
 	}
-	mutex_spin_exit(&rndpool_mtx);
+	mutex_spin_exit(&rndsink_mtx);
 }
 
 void

Index: src/sys/kern/subr_cprng.c
diff -u src/sys/kern/subr_cprng.c:1.5 src/sys/kern/subr_cprng.c:1.6
--- src/sys/kern/subr_cprng.c:1.5	Sat Dec 17 20:05:39 2011
+++ src/sys/kern/subr_cprng.c	Tue Apr 10 14:02:28 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: subr_cprng.c,v 1.5 2011/12/17 20:05:39 tls Exp $ */
+/*	$NetBSD: subr_cprng.c,v 1.6 2012/04/10 14:02:28 tls Exp $ */
 
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -46,7 +46,7 @@
 
 #include <sys/cprng.h>
 
-__KERNEL_RCSID(0, "$NetBSD: subr_cprng.c,v 1.5 2011/12/17 20:05:39 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_cprng.c,v 1.6 2012/04/10 14:02:28 tls Exp $");
 
 void
 cprng_init(void)
@@ -75,10 +75,11 @@ static void
 cprng_strong_sched_reseed(cprng_strong_t *const c)
 {
 	KASSERT(mutex_owned(&c->mtx));
-	if (!(c->reseed_pending)) {
+	if (!(c->reseed_pending) && mutex_tryenter(&c->reseed.mtx)) {
 		c->reseed_pending = 1;
 		c->reseed.len = NIST_BLOCK_KEYLEN_BYTES;
 		rndsink_attach(&c->reseed);
+		mutex_spin_exit(&c->reseed.mtx);
 	}
 }
 
@@ -123,6 +124,7 @@ cprng_strong_create(const char *const na
 	c->reseed_pending = 0;
 	c->reseed.cb = cprng_strong_reseed;
 	c->reseed.arg = c;
+	mutex_init(&c->reseed.mtx, MUTEX_DEFAULT, IPL_VM);
 	strlcpy(c->reseed.name, name, sizeof(c->reseed.name));
 
 	mutex_init(&c->mtx, MUTEX_DEFAULT, ipl);
@@ -266,6 +268,7 @@ cprng_strong(cprng_strong_t *const c, vo
 void
 cprng_strong_destroy(cprng_strong_t *c)
 {
+	mutex_spin_enter(&c->reseed.mtx);
 	mutex_enter(&c->mtx);
 
 	if (c->flags & CPRNG_USE_CV) {
@@ -277,6 +280,8 @@ cprng_strong_destroy(cprng_strong_t *c)
 	if (c->reseed_pending) {
 		rndsink_detach(&c->reseed);
 	}
+	mutex_spin_exit(&c->reseed.mtx);
+
 	nist_ctr_drbg_destroy(&c->drbg);
 
 	mutex_exit(&c->mtx);

Index: src/sys/lib/libkern/arc4random.c
diff -u src/sys/lib/libkern/arc4random.c:1.31 src/sys/lib/libkern/arc4random.c:1.32
--- src/sys/lib/libkern/arc4random.c:1.31	Tue Feb 14 18:57:35 2012
+++ src/sys/lib/libkern/arc4random.c	Tue Apr 10 14:02:28 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: arc4random.c,v 1.31 2012/02/14 18:57:35 njoly Exp $	*/
+/*	$NetBSD: arc4random.c,v 1.32 2012/04/10 14:02:28 tls Exp $	*/
 
 /*-
  * Copyright (c) 2002, 2011 The NetBSD Foundation, Inc.
@@ -167,7 +167,9 @@ arc4_randrekey(void *arg)
 				    "forcibly rekeying.\n");
 				r = rnd_extract_data(key, ARC4_KEYBYTES,
 				    RND_EXTRACT_ANY);
+				mutex_spin_enter(&rs.mtx);
 				rndsink_detach(&rs);
+				mutex_spin_exit(&rs.mtx);
 				callback_pending = 0;
 				goto got_entropy;
 			} else {
@@ -195,11 +197,13 @@ got_entropy:
 		callback_pending = 0;
 	} else if (!callback_pending) {
 		callback_pending = 1;
+		mutex_spin_enter(&rs.mtx);
 		strlcpy(rs.name, "arc4random", sizeof(rs.name));
 		rs.cb = arc4_randrekey;
 		rs.arg = &rs;
 		rs.len = ARC4_KEYBYTES;
 		rndsink_attach(&rs);
+		mutex_spin_exit(&rs.mtx);
 	}
 #endif
 	/*
@@ -260,6 +264,7 @@ arc4_init(void)
 	int n;
 
 	mutex_init(&arc4_mtx, MUTEX_DEFAULT, IPL_VM);
+	mutex_init(&rs.mtx, MUTEX_DEFAULT, IPL_VM);
 	arc4_i = arc4_j = 0;
 	for (n = 0; n < 256; n++)
 		arc4_sbox[n] = (u_int8_t) n;

Index: src/sys/sys/rnd.h
diff -u src/sys/sys/rnd.h:1.29 src/sys/sys/rnd.h:1.30
--- src/sys/sys/rnd.h:1.29	Thu Feb  2 19:43:08 2012
+++ src/sys/sys/rnd.h	Tue Apr 10 14:02:28 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: rnd.h,v 1.29 2012/02/02 19:43:08 tls Exp $	*/
+/*	$NetBSD: rnd.h,v 1.30 2012/04/10 14:02:28 tls Exp $	*/
 
 /*-
  * Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -129,6 +129,7 @@ typedef struct krndsource {
 
 typedef struct rndsink {
         TAILQ_ENTRY(rndsink) tailq;     /* the queue */
+	kmutex_t	mtx;		/* lock to seed or unregister */
         void            (*cb)(void *);  /* callback function when ready */
         void            *arg;           /* callback function argument */
         char            name[16];       /* sink name */

Reply via email to