Module Name: src
Committed By: riz
Date: Thu Apr 19 19:59:11 UTC 2012
Modified Files:
src/sys/dev [netbsd-6]: rndpseudo.c
src/sys/kern [netbsd-6]: kern_rndq.c subr_cprng.c
src/sys/lib/libkern [netbsd-6]: arc4random.c
src/sys/sys [netbsd-6]: rnd.h
Log Message:
Pull up following revision(s) (requested by tls in ticket #185):
sys/kern/subr_cprng.c: revision 1.6
sys/kern/subr_cprng.c: revision 1.7
sys/lib/libkern/arc4random.c: revision 1.32
sys/kern/kern_rndq.c: revision 1.2
sys/dev/rndpseudo.c: revision 1.7
sys/sys/rnd.h: revision 1.30
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.
Fix LOCKDEBUG problems pointed out by drochner@
1) Lock ordering in cprng_strong_destroy had us take a spin mutex then
an adaptive mutex. Can't do that. Reordering this requires changing
cprng_strong_reseed to tryenter the cprng's own mutex and skip the
reseed on failure, or we could deadlock.
2) Can't free memory with a valid mutex in it.
reorder initialization to improve error handling in case the system
runs out of file descriptors, avoids LOCKDEBUG panic due to double
mutex initialization
To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.6.2.1 src/sys/dev/rndpseudo.c
cvs rdiff -u -r1.1 -r1.1.2.1 src/sys/kern/kern_rndq.c
cvs rdiff -u -r1.5 -r1.5.2.1 src/sys/kern/subr_cprng.c
cvs rdiff -u -r1.31 -r1.31.2.1 src/sys/lib/libkern/arc4random.c
cvs rdiff -u -r1.29 -r1.29.2.1 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/dev/rndpseudo.c
diff -u src/sys/dev/rndpseudo.c:1.6 src/sys/dev/rndpseudo.c:1.6.2.1
--- src/sys/dev/rndpseudo.c:1.6 Tue Dec 20 13:42:19 2011
+++ src/sys/dev/rndpseudo.c Thu Apr 19 19:59:11 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: rndpseudo.c,v 1.6 2011/12/20 13:42:19 apb Exp $ */
+/* $NetBSD: rndpseudo.c,v 1.6.2.1 2012/04/19 19:59:11 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 2011/12/20 13:42:19 apb Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rndpseudo.c,v 1.6.2.1 2012/04/19 19:59:11 riz Exp $");
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
@@ -213,15 +213,14 @@ rndopen(dev_t dev, int flag, int ifmt,
default:
return ENXIO;
}
- ctx = pool_cache_get(rp_cpc, PR_WAITOK);
- ctx->cprng = NULL;
- ctx->hard = hard;
- mutex_init(&ctx->interlock, MUTEX_DEFAULT, IPL_NONE);
-
+ ctx = pool_cache_get(rp_cpc, PR_WAITOK);
if ((error = fd_allocfile(&fp, &fd)) != 0) {
pool_cache_put(rp_cpc, ctx);
return error;
}
+ ctx->cprng = NULL;
+ ctx->hard = hard;
+ mutex_init(&ctx->interlock, MUTEX_DEFAULT, IPL_NONE);
return fd_clone(fp, fd, flag, &rnd_fileops, ctx);
}
Index: src/sys/kern/kern_rndq.c
diff -u src/sys/kern/kern_rndq.c:1.1 src/sys/kern/kern_rndq.c:1.1.2.1
--- src/sys/kern/kern_rndq.c:1.1 Thu Feb 2 19:43:07 2012
+++ src/sys/kern/kern_rndq.c Thu Apr 19 19:59:10 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.1.2.1 2012/04/19 19:59:10 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 2012/02/02 19:43:07 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_rndq.c,v 1.1.2.1 2012/04/19 19:59:10 riz 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.5.2.1
--- src/sys/kern/subr_cprng.c:1.5 Sat Dec 17 20:05:39 2011
+++ src/sys/kern/subr_cprng.c Thu Apr 19 19:59:10 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.5.2.1 2012/04/19 19:59:10 riz 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.5.2.1 2012/04/19 19:59:10 riz 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);
}
}
@@ -89,7 +90,10 @@ cprng_strong_reseed(void *const arg)
uint8_t key[NIST_BLOCK_KEYLEN_BYTES];
uint32_t cc = cprng_counter();
- mutex_enter(&c->mtx);
+ if (!mutex_tryenter(&c->mtx)) {
+ return;
+ }
+
if (c->reseed.len != sizeof(key)) {
panic("cprng_strong_reseed: bad entropy length %d "
" (expected %d)", (int)c->reseed.len, (int)sizeof(key));
@@ -123,6 +127,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);
@@ -267,6 +272,7 @@ void
cprng_strong_destroy(cprng_strong_t *c)
{
mutex_enter(&c->mtx);
+ mutex_spin_enter(&c->reseed.mtx);
if (c->flags & CPRNG_USE_CV) {
KASSERT(!cv_has_waiters(&c->cv));
@@ -277,6 +283,9 @@ cprng_strong_destroy(cprng_strong_t *c)
if (c->reseed_pending) {
rndsink_detach(&c->reseed);
}
+ mutex_spin_exit(&c->reseed.mtx);
+ mutex_destroy(&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.31.2.1
--- src/sys/lib/libkern/arc4random.c:1.31 Tue Feb 14 18:57:35 2012
+++ src/sys/lib/libkern/arc4random.c Thu Apr 19 19:59:10 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: arc4random.c,v 1.31 2012/02/14 18:57:35 njoly Exp $ */
+/* $NetBSD: arc4random.c,v 1.31.2.1 2012/04/19 19:59:10 riz 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.29.2.1
--- src/sys/sys/rnd.h:1.29 Thu Feb 2 19:43:08 2012
+++ src/sys/sys/rnd.h Thu Apr 19 19:59:11 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: rnd.h,v 1.29 2012/02/02 19:43:08 tls Exp $ */
+/* $NetBSD: rnd.h,v 1.29.2.1 2012/04/19 19:59:11 riz 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 */