diff --git a/drivers/char/random.c b/drivers/char/random.c index 693640de7271..e7fc274a9608 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -799,16 +799,11 @@ early_param("random.trust_cpu", parse_trust_cpu); early_param("random.trust_bootloader", parse_trust_bootloader); /* - * The first collection of entropy occurs at system boot while interrupts - * are still turned off. Here we push in latent entropy, RDSEED, a timestamp, - * utsname(), and the command line. Depending on the above configuration knob, - * RDSEED may be considered sufficient for initialization. Note that much - * earlier setup may already have pushed entropy into the input pool by the - * time we get here. + * This is called extremely early, before time keeping functionality is + * available, but arch randomness is. Interrupts are not yet enabled. */ -int __init random_init(const char *command_line) +void __init random_init_early(const char *command_line) { - ktime_t now = ktime_get_real(); unsigned int i, arch_bits; unsigned long entropy; @@ -821,22 +816,41 @@ int __init random_init(const char *command_line) i < BLAKE2S_BLOCK_SIZE; i += sizeof(entropy)) { if (!arch_get_random_seed_long_early(&entropy) && !arch_get_random_long_early(&entropy)) { - entropy = random_get_entropy(); arch_bits -= sizeof(entropy) * 8; + continue; } _mix_pool_bytes(&entropy, sizeof(entropy)); } - _mix_pool_bytes(&now, sizeof(now)); - _mix_pool_bytes(utsname(), sizeof(*(utsname()))); - _mix_pool_bytes(command_line, strlen(command_line)); - add_latent_entropy(); + _mix_pool_bytes(command_line, strlen(command_line)); + + /* Reseed if already seeded by earlier phases. */ if (crng_ready()) crng_reseed(); else if (trust_cpu) _credit_init_bits(arch_bits); +} - return 0; +/* + * This is called a little bit after the prior function, and now there is + * access to timestamps counters. Interrupts are not yet enabled. + */ +void __init random_init(void) +{ + unsigned long entropy = random_get_entropy(); + ktime_t now = ktime_get_real(); + + _mix_pool_bytes(utsname(), sizeof(*(utsname()))); + _mix_pool_bytes(&now, sizeof(now)); + _mix_pool_bytes(&entropy, sizeof(entropy)); + add_latent_entropy(); + + /* Reseed if already seeded by earlier phases. */ + if (crng_ready()) + crng_reseed(); + + WARN(!entropy, "Missing cycle counter and fallback timer; RNG " + "entropy collection will consequently suffer."); } /* diff --git a/include/linux/random.h b/include/linux/random.h index 8ed2e245d51e..7e742ef51a83 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -64,7 +64,8 @@ static inline unsigned long get_random_canary(void) return get_random_long() & CANARY_MASK; } -int __init random_init(const char *command_line); +void __init random_init_early(const char *command_line); +void __init random_init(void); bool rng_is_initialized(void); int wait_for_random_bytes(void); int register_random_ready_notifier(struct notifier_block *nb); diff --git a/init/main.c b/init/main.c index d283c689496a..cb6c59db4188 100644 --- a/init/main.c +++ b/init/main.c @@ -625,6 +625,9 @@ asmlinkage __visible void __init start_kernel(void) parse_args("Setting init args", after_dashes, NULL, 0, -1, -1, NULL, set_init_arg); + /* Architectural and non-timekeeping rng init, before allocator init */ + random_init_early(command_line); + /* * These use large bootmem allocations and must precede * kmem_cache_init() @@ -687,17 +690,13 @@ asmlinkage __visible void __init start_kernel(void) hrtimers_init(); softirq_init(); timekeeping_init(); - kfence_init(); time_init(); - /* - * For best initial stack canary entropy, prepare it after: - * - setup_arch() for any UEFI RNG entropy and boot cmdline access - * - timekeeping_init() for ktime entropy used in random_init() - * - time_init() for making random_get_entropy() work on some platforms - * - random_init() to initialize the RNG from from early entropy sources - */ - random_init(command_line); + /* This must be after timekeeping is initialized */ + random_init(); + + /* These make use of the fully initialized rng */ + kfence_init(); boot_init_stack_canary(); perf_event_init();