Module Name: src
Committed By: riastradh
Date: Thu May 7 00:55:13 UTC 2020
Modified Files:
src/sys/kern: kern_entropy.c
Log Message:
Fix two mistakes in entropy accounting.
1. When consolidating entropy from per-CPU pools, drop the amount
pending to zero; otherwise the entropy consolidation thread might
keep consolidating every second.
This uncovered a feedback loop with kern.entropy.depletion=1 and
on-demand entropy sources, which is that depleting the pool and then
requesting more from it causes the on-demand entropy sources to
trigger reseed, which causes cprng_fast/strong to request more which
depletes the pool again which causes on-demand entropy sources to
trigger reseed, and so on.
To work around this:
2. Set a rate limit on reseeding (advancing the entropy epoch) when
kern.entropy.depletion=1; otherwise reseeding gets into a feedback
loop when there are on-demand entropy sources like RDRAND/RDSEED.
(By default, kern.entropy.depletion=0, so this mainly only affects
systems where you're simulating what happens when /dev/random blocks
for testing.)
To generate a diff of this commit:
cvs rdiff -u -r1.11 -r1.12 src/sys/kern/kern_entropy.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/kern/kern_entropy.c
diff -u src/sys/kern/kern_entropy.c:1.11 src/sys/kern/kern_entropy.c:1.12
--- src/sys/kern/kern_entropy.c:1.11 Wed May 6 18:31:05 2020
+++ src/sys/kern/kern_entropy.c Thu May 7 00:55:13 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_entropy.c,v 1.11 2020/05/06 18:31:05 riastradh Exp $ */
+/* $NetBSD: kern_entropy.c,v 1.12 2020/05/07 00:55:13 riastradh Exp $ */
/*-
* Copyright (c) 2019 The NetBSD Foundation, Inc.
@@ -77,7 +77,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_entropy.c,v 1.11 2020/05/06 18:31:05 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_entropy.c,v 1.12 2020/05/07 00:55:13 riastradh Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -1067,8 +1067,9 @@ entropy_gather_xc(void *arg1 __unused, v
__insn_barrier();
extra[i++] = entropy_timer();
- /* Extract the data. */
+ /* Extract the data and count it no longer pending. */
entpool_extract(ec->ec_pool, buf, sizeof buf);
+ atomic_store_relaxed(&ec->ec_pending, 0);
extra[i++] = entropy_timer();
/* Release the per-CPU state. */
@@ -1108,6 +1109,8 @@ entropy_gather_xc(void *arg1 __unused, v
static void
entropy_notify(void)
{
+ static const struct timeval interval = {.tv_sec = 60, .tv_usec = 0};
+ static struct timeval lasttime; /* serialized by E->lock */
unsigned epoch;
KASSERT(E->stage == ENTROPY_COLD || mutex_owned(&E->lock));
@@ -1122,10 +1125,13 @@ entropy_notify(void)
/* Set the epoch; roll over from UINTMAX-1 to 1. */
rnd_initial_entropy = 1; /* XXX legacy */
- epoch = E->epoch + 1;
- if (epoch == 0 || epoch == (unsigned)-1)
- epoch = 1;
- atomic_store_relaxed(&E->epoch, epoch);
+ if (__predict_true(!atomic_load_relaxed(&entropy_depletion)) ||
+ ratecheck(&lasttime, &interval)) {
+ epoch = E->epoch + 1;
+ if (epoch == 0 || epoch == (unsigned)-1)
+ epoch = 1;
+ atomic_store_relaxed(&E->epoch, epoch);
+ }
/* Notify waiters. */
if (E->stage >= ENTROPY_WARM) {