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 */