[RFC PATCH 40/41] random: trigger startup health test on any failure of the health tests

From: Nicolai Stange
Date: Mon Sep 21 2020 - 04:01:41 EST


The startup health tests to be executed at boot as required by NIST 800-90B
consist of running the contiuous health tests, i.e. the Adaptive Proportion
Test (APT) and the Repetition Count Test (RCT), until a certain amount
of noise samples have been examined. In case of test failure during this
period, the startup tests would get restarted by means of reinitializing
the fast_pool's ->warmup member with the original number of total samples
to examine during startup.

A future patch will enable dynamically switching from the initial H=1 or
1/8 per-IRQ min-entropy estimates to lower values upon health test
failures in order to keep those systems going where these more or less
arbitrary per-IRQ entropy estimates turn out to simply be wrong. It is
certainly desirable to restart the startup health tests upon such a switch.

In order to keep the upcoming code comprehensible, move the startup test
restart logic from health_test_process() into add_interrupt_randomness().
For simplicity, make add_interrupt_randomness() trigger a startup test on
each health test failure. Note that there's a change in behaviour: up to
now, only the bootime startup tests would have restarted themselves upon
failure, whereas now even a failure of the continuous health tests can
potentially trigger a startup test long after boot.

Note that as it currently stands, rerunning the full startup tests after
the crng has received its initial seed has the only effect to inhibit
entropy dispatch for a while and thus, to potentially delay those best
effort crng reseeds during runtime. As reseeds never reduce a crng state's
entropy, this behaviour is admittedly questionable. However, further
patches introducing forced reseeds might perhaps become necessary in the
future, c.f. the specification of "reseed_interval" in NIST SP800-90A.
Thus, it's better to keep the startup health test restart logic consistent
for now.

Signed-off-by: Nicolai Stange <nstange@xxxxxxx>
---
drivers/char/random.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/char/random.c b/drivers/char/random.c
index 86dd87588b1b..bb79dcb96882 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1098,8 +1098,6 @@ health_test_process(struct health_test *h, unsigned int event_entropy_shift,
* Something is really off, get_cycles() has become
* (or always been) a constant.
*/
- if (h->warmup)
- health_test_reset(h, event_entropy_shift);
return health_discard;
}

@@ -1110,8 +1108,6 @@ health_test_process(struct health_test *h, unsigned int event_entropy_shift,
*/
apt = health_test_apt(h, event_entropy_shift, sample_delta);
if (unlikely(h->warmup) && --h->warmup) {
- if (apt == health_discard)
- health_test_reset(h, event_entropy_shift);
/*
* Don't allow the caller to dispatch until warmup
* has completed.
@@ -1928,6 +1924,14 @@ void add_interrupt_randomness(int irq, int irq_flags)
health_test_process(&fast_pool->health,
fast_pool->event_entropy_shift,
cycles);
+ if (unlikely(health_result == health_discard)) {
+ /*
+ * Oops, something's odd. Restart the startup
+ * tests.
+ */
+ health_test_reset(&fast_pool->health,
+ fast_pool->event_entropy_shift);
+ }
}

if (unlikely(crng_init == 0)) {
--
2.26.2