Commit 31c0aa87 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull /dev/random updates from Ted Ts'o:

 - Improve getrandom and /dev/random's support for those arm64
   architecture variants that have RNG instructions.

 - Use batched output from CRNG instead of CPU's RNG instructions for
   better performance.

 - Miscellaneous bug fixes.

* tag 'random_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/random:
  random: avoid warnings for !CONFIG_NUMA builds
  random: fix data races at timer_rand_state
  random: always use batched entropy for get_random_u{32,64}
  random: Make RANDOM_TRUST_CPU depend on ARCH_RANDOM
  arm64: add credited/trusted RNG support
  random: add arch_get_random_*long_early()
  random: split primary/secondary crng init paths
parents 9c94b395 ab9a7e27
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -4,6 +4,8 @@

#ifdef CONFIG_ARCH_RANDOM

#include <linux/bug.h>
#include <linux/kernel.h>
#include <linux/random.h>
#include <asm/cpufeature.h>

@@ -66,6 +68,18 @@ static inline bool __init __early_cpu_has_rndr(void)
	return (ftr >> ID_AA64ISAR0_RNDR_SHIFT) & 0xf;
}

static inline bool __init __must_check
arch_get_random_seed_long_early(unsigned long *v)
{
	WARN_ON(system_state != SYSTEM_BOOTING);

	if (!__early_cpu_has_rndr())
		return false;

	return __arm64_rndr(v);
}
#define arch_get_random_seed_long_early arch_get_random_seed_long_early

#else

static inline bool __arm64_rndr(unsigned long *v) { return false; }
+1 −1
Original line number Diff line number Diff line
@@ -474,7 +474,7 @@ endmenu

config RANDOM_TRUST_CPU
	bool "Trust the CPU manufacturer to initialize Linux's CRNG"
	depends on X86 || S390 || PPC
	depends on ARCH_RANDOM
	default n
	help
	Assume that CPU manufacturer (e.g., Intel or AMD for RDSEED or
+50 −34
Original line number Diff line number Diff line
@@ -781,27 +781,55 @@ static int __init parse_trust_cpu(char *arg)
}
early_param("random.trust_cpu", parse_trust_cpu);

static void crng_initialize(struct crng_state *crng)
static bool crng_init_try_arch(struct crng_state *crng)
{
	int		i;
	int		arch_init = 1;
	bool		arch_init = true;
	unsigned long	rv;

	memcpy(&crng->state[0], "expand 32-byte k", 16);
	if (crng == &primary_crng)
		_extract_entropy(&input_pool, &crng->state[4],
				 sizeof(__u32) * 12, 0);
	else
		_get_random_bytes(&crng->state[4], sizeof(__u32) * 12);
	for (i = 4; i < 16; i++) {
		if (!arch_get_random_seed_long(&rv) &&
		    !arch_get_random_long(&rv)) {
			rv = random_get_entropy();
			arch_init = 0;
			arch_init = false;
		}
		crng->state[i] ^= rv;
	}

	return arch_init;
}

static bool __init crng_init_try_arch_early(struct crng_state *crng)
{
	int		i;
	bool		arch_init = true;
	unsigned long	rv;

	for (i = 4; i < 16; i++) {
		if (!arch_get_random_seed_long_early(&rv) &&
		    !arch_get_random_long_early(&rv)) {
			rv = random_get_entropy();
			arch_init = false;
		}
		crng->state[i] ^= rv;
	}
	if (trust_cpu && arch_init && crng == &primary_crng) {

	return arch_init;
}

static void __maybe_unused crng_initialize_secondary(struct crng_state *crng)
{
	memcpy(&crng->state[0], "expand 32-byte k", 16);
	_get_random_bytes(&crng->state[4], sizeof(__u32) * 12);
	crng_init_try_arch(crng);
	crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1;
}

static void __init crng_initialize_primary(struct crng_state *crng)
{
	memcpy(&crng->state[0], "expand 32-byte k", 16);
	_extract_entropy(&input_pool, &crng->state[4], sizeof(__u32) * 12, 0);
	if (crng_init_try_arch_early(crng) && trust_cpu) {
		invalidate_batched_entropy();
		numa_crng_init();
		crng_init = 2;
@@ -822,7 +850,7 @@ static void do_numa_crng_init(struct work_struct *work)
		crng = kmalloc_node(sizeof(struct crng_state),
				    GFP_KERNEL | __GFP_NOFAIL, i);
		spin_lock_init(&crng->lock);
		crng_initialize(crng);
		crng_initialize_secondary(crng);
		pool[i] = crng;
	}
	mb();
@@ -1142,14 +1170,14 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
	 * We take into account the first, second and third-order deltas
	 * in order to make our estimate.
	 */
	delta = sample.jiffies - state->last_time;
	state->last_time = sample.jiffies;
	delta = sample.jiffies - READ_ONCE(state->last_time);
	WRITE_ONCE(state->last_time, sample.jiffies);

	delta2 = delta - state->last_delta;
	state->last_delta = delta;
	delta2 = delta - READ_ONCE(state->last_delta);
	WRITE_ONCE(state->last_delta, delta);

	delta3 = delta2 - state->last_delta2;
	state->last_delta2 = delta2;
	delta3 = delta2 - READ_ONCE(state->last_delta2);
	WRITE_ONCE(state->last_delta2, delta2);

	if (delta < 0)
		delta = -delta;
@@ -1771,7 +1799,7 @@ static void __init init_std_data(struct entropy_store *r)
int __init rand_initialize(void)
{
	init_std_data(&input_pool);
	crng_initialize(&primary_crng);
	crng_initialize_primary(&primary_crng);
	crng_global_init_time = jiffies;
	if (ratelimit_disable) {
		urandom_warning.interval = 0;
@@ -2149,11 +2177,11 @@ struct batched_entropy {

/*
 * Get a random word for internal kernel use only. The quality of the random
 * number is either as good as RDRAND or as good as /dev/urandom, with the
 * goal of being quite fast and not depleting entropy. In order to ensure
 * number is good as /dev/urandom, but there is no backtrack protection, with
 * the goal of being quite fast and not depleting entropy. In order to ensure
 * that the randomness provided by this function is okay, the function
 * wait_for_random_bytes() should be called and return 0 at least once
 * at any point prior.
 * wait_for_random_bytes() should be called and return 0 at least once at any
 * point prior.
 */
static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64) = {
	.batch_lock	= __SPIN_LOCK_UNLOCKED(batched_entropy_u64.lock),
@@ -2166,15 +2194,6 @@ u64 get_random_u64(void)
	struct batched_entropy *batch;
	static void *previous;

#if BITS_PER_LONG == 64
	if (arch_get_random_long((unsigned long *)&ret))
		return ret;
#else
	if (arch_get_random_long((unsigned long *)&ret) &&
	    arch_get_random_long((unsigned long *)&ret + 1))
	    return ret;
#endif

	warn_unseeded_randomness(&previous);

	batch = raw_cpu_ptr(&batched_entropy_u64);
@@ -2199,9 +2218,6 @@ u32 get_random_u32(void)
	struct batched_entropy *batch;
	static void *previous;

	if (arch_get_random_int(&ret))
		return ret;

	warn_unseeded_randomness(&previous);

	batch = raw_cpu_ptr(&batched_entropy_u32);
+22 −0
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@
#ifndef _LINUX_RANDOM_H
#define _LINUX_RANDOM_H

#include <linux/bug.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/once.h>

@@ -185,6 +187,26 @@ static inline bool __must_check arch_get_random_seed_int(unsigned int *v)
}
#endif

/*
 * Called from the boot CPU during startup; not valid to call once
 * secondary CPUs are up and preemption is possible.
 */
#ifndef arch_get_random_seed_long_early
static inline bool __init arch_get_random_seed_long_early(unsigned long *v)
{
	WARN_ON(system_state != SYSTEM_BOOTING);
	return arch_get_random_seed_long(v);
}
#endif

#ifndef arch_get_random_long_early
static inline bool __init arch_get_random_long_early(unsigned long *v)
{
	WARN_ON(system_state != SYSTEM_BOOTING);
	return arch_get_random_long(v);
}
#endif

/* Pseudo random number generator from numerical recipes. */
static inline u32 next_pseudo_random32(u32 seed)
{