NIST SP800-90B, section 4.3 requires an entropy source to inhibit output until the so-called "startup" tests have completed. These "startup" test shall process at least 1024 consecutive samples by means of the continuous health tests, i.e. the already implemented Repetition Count Test (RCT) and Adaptive Proportion Test (APT). Introduce a new field ->warmup to struct health_test. Initialize it to 1024 from health_test_reset(). Make health_test_process() decrement ->warmup once per event processed without test failure, but reset ->warmup to the intitial value upon failure. Prevent health_test_process() from returning health_dispatch as long as ->warmup hasn't dropped to zero. This will cause the caller, i.e. add_interrupt_randomness(), to not dispatch any entropy to the global balance until the startup tests have finished. Note that this change will delay the initial seeding of the primary_crng, especially for those values of the estimated per-IRQ min-entropy H where the mimimum of 1024 events from above is by several factors larger than 128/H, the number of events to be processed by a single APT run. That would only affect systems running with fips_enabled though and there's simply no way to avoid it without violating the specs. Signed-off-by: Nicolai Stange <nstange@xxxxxxx> --- drivers/char/random.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 54ee082ca4a8..bd8c24e433d0 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -880,6 +880,7 @@ static void discard_queued_entropy(struct entropy_store *r, } struct health_test { + unsigned short warmup; unsigned short apt_event_count; union { u32 apt_presearch_bit_counters; @@ -1059,6 +1060,13 @@ health_test_apt(struct health_test *h, unsigned int event_entropy_shift, static void health_test_reset(struct health_test *h) { + /* + * Don't dispatch until at least 1024 events have been + * processed by the continuous health tests as required by + * NIST SP800-90B for the startup tests. + */ + h->warmup = 1024; + health_apt_reset(h); } @@ -1067,7 +1075,7 @@ health_test_process(struct health_test *h, unsigned int event_entropy_shift, u8 sample) { u8 sample_delta; - enum health_result rct; + enum health_result rct, apt; /* * The min-entropy estimate has been made for the lower eight @@ -1083,6 +1091,8 @@ 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); return health_discard; } @@ -1091,7 +1101,18 @@ health_test_process(struct health_test *h, unsigned int event_entropy_shift, * don't care about whether the RCT needs to consume more * samples to complete. */ - return health_test_apt(h, event_entropy_shift, sample_delta); + apt = health_test_apt(h, event_entropy_shift, sample_delta); + if (unlikely(h->warmup) && --h->warmup) { + if (apt == health_discard) + health_test_reset(h); + /* + * Don't allow the caller to dispatch until warmup + * has completed. + */ + return apt == health_dispatch ? health_queue : apt; + } + + return apt; } struct fast_pool { -- 2.26.2