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
This commit is contained in:
Colin Percival 2022-07-12 17:48:06 -07:00
parent 102f31bf36
commit 0811ce5723

View File

@ -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.