Fix two problems that could cause /dev/random to not wake up readers when entropy became available.
This commit is contained in:
parent
1818db7635
commit
a918f11452
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue