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.
This commit is contained in:
parent
23fb23b458
commit
2b09c6c851
@ -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
|
||||
|
@ -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 name, int ipl, int flags)
|
||||
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, void *const p, size_t len, int flags)
|
||||
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);
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user