Correct use of entropy estimate when data are extracted from the pool.

The "threshold" value was being inappropriately used to limit how many
bytes could be output even after the estimator said enough bytes had
been put in to meet our minimum security guarantee.

This fixes a panic observed with the automatic test harness and by
msaitoh, where it was not possible to extract the full estimate's worth
of bytes even holding the pool lock across the estimate and extract
calls.
This commit is contained in:
tls 2013-06-13 19:18:00 +00:00
parent c42e7a1ab0
commit a5fd1fb2d3

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_rndpool.c,v 1.3 2013/06/13 00:55:01 tls Exp $ */
/* $NetBSD: kern_rndpool.c,v 1.4 2013/06/13 19:18:00 tls Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_rndpool.c,v 1.3 2013/06/13 00:55:01 tls Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_rndpool.c,v 1.4 2013/06/13 19:18:00 tls Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -57,6 +57,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_rndpool.c,v 1.3 2013/06/13 00:55:01 tls Exp $")
int rnd_full = 0; /* Flag: is the pool full? */
int rnd_filled = 0; /* Count: how many times filled? */
int rnd_empty = 1; /* Flag: is the pool empty? */
extern int rnd_initial_entropy; /* Have ever hit the "threshold" */
static inline void rndpool_add_one_word(rndpool_t *, u_int32_t);
@ -235,8 +236,11 @@ rndpool_add_data(rndpool_t *rp, void *p, u_int32_t len, u_int32_t entropy)
* the hash are xored together before being returned.
*
* Honor the request from the caller to only return good data, any data,
* etc. Note that we must have at least 64 bits of entropy in the pool
* before we return anything in the high-quality modes.
* etc.
*
* For the "high-quality" mode, we must have as much data as the caller
* requests, and at some point we must have had at least the "threshold"
* amount of entropy in the pool.
*/
u_int32_t
rndpool_extract_data(rndpool_t *rp, void *p, u_int32_t len, u_int32_t mode)
@ -246,7 +250,6 @@ rndpool_extract_data(rndpool_t *rp, void *p, u_int32_t len, u_int32_t mode)
u_char digest[SHA1_DIGEST_LENGTH];
u_int32_t remain, deltae, count;
u_int8_t *buf;
int good;
buf = p;
remain = len;
@ -255,14 +258,10 @@ rndpool_extract_data(rndpool_t *rp, void *p, u_int32_t len, u_int32_t mode)
rnd_full = 0;
}
if (mode == RND_EXTRACT_ANY)
good = 1;
else
good = (rp->stats.curentropy >= (8 * RND_ENTROPY_THRESHOLD));
KASSERT(RND_ENTROPY_THRESHOLD * 2 <= sizeof(digest));
while (good && (remain != 0)) {
while (remain != 0 && ! (mode == RND_EXTRACT_GOOD &&
remain > rp->stats.curentropy * 8)) {
/*
* While bytes are requested, compute the hash of the pool,
* and then "fold" the hash in half with XOR, keeping the
@ -289,6 +288,7 @@ rndpool_extract_data(rndpool_t *rp, void *p, u_int32_t len, u_int32_t mode)
rndpool_add_one_word(rp, word);
}
/* XXX careful, here the THRESHOLD just controls folding */
count = min(remain, RND_ENTROPY_THRESHOLD);
for (i = 0; i < count; i++)
@ -306,9 +306,6 @@ rndpool_extract_data(rndpool_t *rp, void *p, u_int32_t len, u_int32_t mode)
if (rp->stats.curentropy == 0)
rp->stats.generated += (count * 8) - deltae;
if (mode == RND_EXTRACT_GOOD)
good = (rp->stats.curentropy >=
(8 * RND_ENTROPY_THRESHOLD));
}
memset(&hash, 0, sizeof(hash));