git: 0811ce572394 - main - random: Ingest extra fast entropy when !seeded

From: Colin Percival <cperciva_at_FreeBSD.org>
Date: Wed, 20 Jul 2022 07:00:04 UTC
The branch main has been updated by cperciva:

URL: https://cgit.FreeBSD.org/src/commit/?id=0811ce572394707affe3ad6c17493585940d8ab3

commit 0811ce572394707affe3ad6c17493585940d8ab3
Author:     Colin Percival <cperciva@FreeBSD.org>
AuthorDate: 2022-07-13 00:48:06 +0000
Commit:     Colin Percival <cperciva@FreeBSD.org>
CommitDate: 2022-07-20 06:59:40 +0000

    random: Ingest extra fast entropy when !seeded
    
    We periodically ingest entropy from pollable entropy sources, but only
    8 bytes at a time and only occasionally enough to feed all of Fortuna's
    pools once per second.  This can result in Fortuna remaining unseeded
    for a nontrivial amount of time when there is no entropy passed in from
    the boot loader, even if RDRAND is available to quickly provide a large
    amount of entropy.
    
    Detect in random_sources_feed if we are not yet seeded, and increase the
    amount of immediate entropy harvesting we perform, in order to "fill"
    Fortuna's entropy pools and avoid having
      random: randomdev_wait_until_seeded unblock wait
    stall the boot process when entropy is available.
    
    This speeds up the FreeBSD boot in the Firecracker VM by 2.3 seconds.
    
    Approved by:    csprng (delphij)
    Sponsored by:   https://www.patreon.com/cperciva
    Differential Revision:  https://reviews.freebsd.org/D35802
---
 sys/dev/random/random_harvestq.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c
index 1eeb46a22073..cea3f51893a8 100644
--- a/sys/dev/random/random_harvestq.c
+++ b/sys/dev/random/random_harvestq.c
@@ -254,6 +254,28 @@ random_sources_feed(void)
 	 */
 	npools = howmany(p_random_alg_context->ra_poolcount, RANDOM_KTHREAD_HZ);
 
+	/*-
+	 * If we're not seeded yet, attempt to perform a "full seed", filling
+	 * all of the PRNG's pools with entropy; if there is enough entropy
+	 * available from "fast" entropy sources this will allow us to finish
+	 * seeding and unblock the boot process immediately rather than being
+	 * stuck for a few seconds with random_kthread gradually collecting a
+	 * small chunk of entropy every 1 / RANDOM_KTHREAD_HZ seconds.
+	 *
+	 * The value 64 below is RANDOM_FORTUNA_DEFPOOLSIZE, i.e. chosen to
+	 * fill Fortuna's pools in the default configuration.  With another
+	 * PRNG or smaller pools for Fortuna, we might collect more entropy
+	 * than needed to fill the pools, but this is harmless; alternatively,
+	 * a different PRNG, larger pools, or fast entropy sources which are
+	 * not able to provide as much entropy as we request may result in the
+	 * not being fully seeded (and thus remaining blocked) but in that
+	 * case we will return here after 1 / RANDOM_KTHREAD_HZ seconds and
+	 * try again for a large amount of entropy.
+	 */
+	if (!p_random_alg_context->ra_seeded())
+		npools = howmany(p_random_alg_context->ra_poolcount * 64,
+		    sizeof(entropy));
+
 	/*
 	 * Step over all of live entropy sources, and feed their output
 	 * to the system-wide RNG.