On Sat, Mar 12, 2022 at 06:41:10PM -0700, Jason A. Donenfeld wrote: > In order to chip away at the "premature first" problem, we augment our > existing entropy accounting with more frequent reseedings at boot. > > The idea is that at boot, we're getting entropy from various places, and > we're not very sure which of early boot entropy is good and which isn't. > Even when we're crediting the entropy, we're still not totally certain > that it's any good. Since boot is the one time (aside from a compromise) > that we have zero entropy, it's important that we shepherd entropy into > the crng fairly often. > > At the same time, we don't want a "premature next" problem, whereby an > attacker can brute force individual bits of added entropy. In lieu of > going full-on Fortuna (for now), we can pick a simpler strategy of just > reseeding more often during the first 5 minutes after boot. This is > still bounded by the 256-bit entropy credit requirement, so we'll skip a > reseeding if we haven't reached that, but in case entropy /is/ coming > in, this ensures that it makes its way into the crng rather rapidly > during these early stages. > > Ordinarily we reseed if the previous reseeding is 300 seconds old. This > commit changes things so that for the first 600 seconds of boot time, we > reseed if the previous reseeding is uptime / 2 seconds old. That means > that we'll reseed at the very least double the uptime of the previous > reseeding. > > Cc: Theodore Ts'o <tytso@xxxxxxx> > Cc: Dominik Brodowski <linux@xxxxxxxxxxxxxxxxxxxx> > Cc: Eric Biggers <ebiggers@xxxxxxxxxx> > Signed-off-by: Jason A. Donenfeld <Jason@xxxxxxxxx> > --- > v4 uses Eric's formulation relative to the last reseed time, rather than > my prior one relative to boot time alone. > > drivers/char/random.c | 28 +++++++++++++++++++++++++--- > 1 file changed, 25 insertions(+), 3 deletions(-) > > diff --git a/drivers/char/random.c b/drivers/char/random.c > index 19a602c69f2f..defdba110d1d 100644 > --- a/drivers/char/random.c > +++ b/drivers/char/random.c > @@ -327,6 +327,28 @@ static void crng_fast_key_erasure(u8 key[CHACHA_KEY_SIZE], > memzero_explicit(first_block, sizeof(first_block)); > } > > +/* > + * Return whether the crng seed is considered to be sufficiently > + * old that a reseeding might be attempted. This happens if the last > + * reseeding was CRNG_RESEED_INTERVAL ago, or during early boot, at > + * an interval proportional to the uptime. > + */ > +static bool crng_has_old_seed(void) > +{ > + static bool early_boot = true; > + unsigned long interval = CRNG_RESEED_INTERVAL; > + > + if (unlikely(READ_ONCE(early_boot))) { > + time64_t uptime = ktime_get_seconds(); > + if (uptime >= CRNG_RESEED_INTERVAL / HZ * 2) > + WRITE_ONCE(early_boot, false); > + else > + interval = max_t(unsigned int, 5 * HZ, > + (unsigned int)uptime / 2 * HZ); > + } > + return time_after(jiffies, READ_ONCE(base_crng.birth) + interval); > +} > + > /* > * This function returns a ChaCha state that you may use for generating > * random data. It also returns up to 32 bytes on its own of random data > @@ -360,10 +382,10 @@ static void crng_make_state(u32 chacha_state[CHACHA_STATE_WORDS], > } > > /* > - * If the base_crng is more than 5 minutes old, we reseed, which > - * in turn bumps the generation counter that we check below. > + * If the base_crng is old enough, we try to reseed, which in turn > + * bumps the generation counter that we check below. > */ > - if (unlikely(time_after(jiffies, READ_ONCE(base_crng.birth) + CRNG_RESEED_INTERVAL))) > + if (unlikely(crng_has_old_seed())) > crng_reseed(false); > Looks good, Reviewed-by: Eric Biggers <ebiggers@xxxxxxxxxx> - Eric