Fix two problems that could cause /dev/random to not wake up readers when entropy became available.

This commit is contained in:
tls 2012-05-19 16:00:41 +00:00
parent 1818db7635
commit a918f11452
2 changed files with 42 additions and 27 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: rndpseudo.c,v 1.9 2012/04/20 21:57:33 tls Exp $ */ /* $NetBSD: rndpseudo.c,v 1.10 2012/05/19 16:00:41 tls Exp $ */
/*- /*-
* Copyright (c) 1997-2011 The NetBSD Foundation, Inc. * Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@ -30,7 +30,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: rndpseudo.c,v 1.9 2012/04/20 21:57:33 tls Exp $"); __KERNEL_RCSID(0, "$NetBSD: rndpseudo.c,v 1.10 2012/05/19 16:00:41 tls Exp $");
#if defined(_KERNEL_OPT) #if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h" #include "opt_compat_netbsd.h"
@ -309,14 +309,23 @@ rnd_read(struct file * fp, off_t *offp, struct uio *uio,
/* XXX is this _really_ what's wanted? */ /* XXX is this _really_ what's wanted? */
if (ctx->hard) { if (ctx->hard) {
n = MIN(want, strength - ctx->bytesonkey); n = MIN(want, strength - ctx->bytesonkey);
ctx->bytesonkey += n; if (n < 1) {
cprng_strong_deplete(cprng);
n = MIN(want, strength);
ctx->bytesonkey = 0;
membar_producer();
}
} else { } else {
n = want; n = want;
} }
nread = cprng_strong(cprng, bf, n, nread = cprng_strong(cprng, bf, n,
(fp->f_flag & FNONBLOCK) ? FNONBLOCK : 0); (fp->f_flag & FNONBLOCK) ? FNONBLOCK : 0);
if (nread != n) {
if (ctx->hard && nread > 0) {
atomic_add_int(&ctx->bytesonkey, nread);
}
if (nread < 1) {
if (fp->f_flag & FNONBLOCK) { if (fp->f_flag & FNONBLOCK) {
ret = EWOULDBLOCK; ret = EWOULDBLOCK;
} else { } else {
@ -331,12 +340,6 @@ rnd_read(struct file * fp, off_t *offp, struct uio *uio,
} }
} }
out: out:
if (ctx->bytesonkey >= strength) {
/* Force reseed of underlying DRBG (prediction resistance) */
cprng_strong_deplete(cprng);
ctx->bytesonkey = 0;
}
pool_cache_put(rp_pc, bf); pool_cache_put(rp_pc, bf);
return (ret); return (ret);
} }

View File

@ -1,4 +1,4 @@
/* $NetBSD: subr_cprng.c,v 1.8 2012/04/17 02:50:39 tls Exp $ */ /* $NetBSD: subr_cprng.c,v 1.9 2012/05/19 16:00:41 tls Exp $ */
/*- /*-
* Copyright (c) 2011 The NetBSD Foundation, Inc. * Copyright (c) 2011 The NetBSD Foundation, Inc.
@ -46,7 +46,7 @@
#include <sys/cprng.h> #include <sys/cprng.h>
__KERNEL_RCSID(0, "$NetBSD: subr_cprng.c,v 1.8 2012/04/17 02:50:39 tls Exp $"); __KERNEL_RCSID(0, "$NetBSD: subr_cprng.c,v 1.9 2012/05/19 16:00:41 tls Exp $");
void void
cprng_init(void) cprng_init(void)
@ -144,6 +144,9 @@ cprng_strong_reseed(void *const arg)
#ifdef RND_VERBOSE #ifdef RND_VERBOSE
printf("cprng: sink %s cprng busy, no reseed\n", c->reseed.name); printf("cprng: sink %s cprng busy, no reseed\n", c->reseed.name);
#endif #endif
if (c->flags & CPRNG_USE_CV) { /* XXX if flags change? */
cv_broadcast(&c->cv);
}
return; return;
} }
@ -240,23 +243,32 @@ cprng_strong(cprng_strong_t *const c, void *const p, size_t len, int flags)
"failed.", c->name); "failed.", c->name);
} }
} else { } else {
if (!(flags & FNONBLOCK) && int wr;
(c->flags & CPRNG_USE_CV)) {
int wr;
do {
cprng_strong_sched_reseed(c); cprng_strong_sched_reseed(c);
do { if ((flags & FNONBLOCK) ||
wr = cv_wait_sig(&c->cv, &c->mtx); !(c->flags & CPRNG_USE_CV)) {
if (wr == ERESTART) { len = 0;
mutex_exit(&c->mtx); break;
return 0; }
} /*
} while (nist_ctr_drbg_generate(&c->drbg, p, * XXX There's a race with the cv_broadcast
len, &cc, * XXX in cprng_strong_sched_reseed, because
sizeof(cc))); * XXX of the use of tryenter in that function.
} else { * XXX This "timedwait" hack works around it,
len = 0; * XXX at the expense of occasionaly polling
} * XXX for success on a /dev/random rekey.
*/
wr = cv_timedwait_sig(&c->cv, &c->mtx,
mstohz(100));
if (wr == ERESTART) {
mutex_exit(&c->mtx);
return 0;
}
} while (nist_ctr_drbg_generate(&c->drbg, p,
len, &cc,
sizeof(cc)));
} }
} }