mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	random32: make prandom_u32() output unpredictable
Non-cryptographic PRNGs may have great statistical properties, but are usually trivially predictable to someone who knows the algorithm, given a small sample of their output. An LFSR like prandom_u32() is particularly simple, even if the sample is widely scattered bits. It turns out the network stack uses prandom_u32() for some things like random port numbers which it would prefer are *not* trivially predictable. Predictability led to a practical DNS spoofing attack. Oops. This patch replaces the LFSR with a homebrew cryptographic PRNG based on the SipHash round function, which is in turn seeded with 128 bits of strong random key. (The authors of SipHash have *not* been consulted about this abuse of their algorithm.) Speed is prioritized over security; attacks are rare, while performance is always wanted. Replacing all callers of prandom_u32() is the quick fix. Whether to reinstate a weaker PRNG for uses which can tolerate it is an open question. Commitf227e3ec3b("random32: update the net random state on interrupt and activity") was an earlier attempt at a solution. This patch replaces it. Reported-by: Amit Klein <aksecurity@gmail.com> Cc: Willy Tarreau <w@1wt.eu> Cc: Eric Dumazet <edumazet@google.com> Cc: "Jason A. Donenfeld" <Jason@zx2c4.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: Kees Cook <keescook@chromium.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: tytso@mit.edu Cc: Florian Westphal <fw@strlen.de> Cc: Marc Plumb <lkml.mplumb@gmail.com> Fixes:f227e3ec3b("random32: update the net random state on interrupt and activity") Signed-off-by: George Spelvin <lkml@sdf.org> Link: https://lore.kernel.org/netdev/20200808152628.GA27941@SDF.ORG/ [ willy: partial reversal of f227e3ec3b5c; moved SIPROUND definitions to prandom.h for later use; merged George's prandom_seed() proposal; inlined siprand_u32(); replaced the net_rand_state[] array with 4 members to fix a build issue; cosmetic cleanups to make checkpatch happy; fixed RANDOM32_SELFTEST build ] Signed-off-by: Willy Tarreau <w@1wt.eu>
This commit is contained in:
		
							parent
							
								
									f11901ed72
								
							
						
					
					
						commit
						c51f8f88d7
					
				
					 4 changed files with 318 additions and 190 deletions
				
			
		| 
						 | 
					@ -1277,7 +1277,6 @@ void add_interrupt_randomness(int irq, int irq_flags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fast_mix(fast_pool);
 | 
						fast_mix(fast_pool);
 | 
				
			||||||
	add_interrupt_bench(cycles);
 | 
						add_interrupt_bench(cycles);
 | 
				
			||||||
	this_cpu_add(net_rand_state.s1, fast_pool->pool[cycles & 3]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (unlikely(crng_init == 0)) {
 | 
						if (unlikely(crng_init == 0)) {
 | 
				
			||||||
		if ((fast_pool->count >= 64) &&
 | 
							if ((fast_pool->count >= 64) &&
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,12 +16,44 @@ void prandom_bytes(void *buf, size_t nbytes);
 | 
				
			||||||
void prandom_seed(u32 seed);
 | 
					void prandom_seed(u32 seed);
 | 
				
			||||||
void prandom_reseed_late(void);
 | 
					void prandom_reseed_late(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if BITS_PER_LONG == 64
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The core SipHash round function.  Each line can be executed in
 | 
				
			||||||
 | 
					 * parallel given enough CPU resources.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define PRND_SIPROUND(v0, v1, v2, v3) ( \
 | 
				
			||||||
 | 
						v0 += v1, v1 = rol64(v1, 13),  v2 += v3, v3 = rol64(v3, 16), \
 | 
				
			||||||
 | 
						v1 ^= v0, v0 = rol64(v0, 32),  v3 ^= v2,                     \
 | 
				
			||||||
 | 
						v0 += v3, v3 = rol64(v3, 21),  v2 += v1, v1 = rol64(v1, 17), \
 | 
				
			||||||
 | 
						v3 ^= v0,                      v1 ^= v2, v2 = rol64(v2, 32)  \
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PRND_K0 (0x736f6d6570736575 ^ 0x6c7967656e657261)
 | 
				
			||||||
 | 
					#define PRND_K1 (0x646f72616e646f6d ^ 0x7465646279746573)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif BITS_PER_LONG == 32
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * On 32-bit machines, we use HSipHash, a reduced-width version of SipHash.
 | 
				
			||||||
 | 
					 * This is weaker, but 32-bit machines are not used for high-traffic
 | 
				
			||||||
 | 
					 * applications, so there is less output for an attacker to analyze.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define PRND_SIPROUND(v0, v1, v2, v3) ( \
 | 
				
			||||||
 | 
						v0 += v1, v1 = rol32(v1,  5),  v2 += v3, v3 = rol32(v3,  8), \
 | 
				
			||||||
 | 
						v1 ^= v0, v0 = rol32(v0, 16),  v3 ^= v2,                     \
 | 
				
			||||||
 | 
						v0 += v3, v3 = rol32(v3,  7),  v2 += v1, v1 = rol32(v1, 13), \
 | 
				
			||||||
 | 
						v3 ^= v0,                      v1 ^= v2, v2 = rol32(v2, 16)  \
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					#define PRND_K0 0x6c796765
 | 
				
			||||||
 | 
					#define PRND_K1 0x74656462
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#error Unsupported BITS_PER_LONG
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rnd_state {
 | 
					struct rnd_state {
 | 
				
			||||||
	__u32 s1, s2, s3, s4;
 | 
						__u32 s1, s2, s3, s4;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DECLARE_PER_CPU(struct rnd_state, net_rand_state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
u32 prandom_u32_state(struct rnd_state *state);
 | 
					u32 prandom_u32_state(struct rnd_state *state);
 | 
				
			||||||
void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes);
 | 
					void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes);
 | 
				
			||||||
void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state);
 | 
					void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1717,13 +1717,6 @@ void update_process_times(int user_tick)
 | 
				
			||||||
	scheduler_tick();
 | 
						scheduler_tick();
 | 
				
			||||||
	if (IS_ENABLED(CONFIG_POSIX_TIMERS))
 | 
						if (IS_ENABLED(CONFIG_POSIX_TIMERS))
 | 
				
			||||||
		run_posix_cpu_timers();
 | 
							run_posix_cpu_timers();
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* The current CPU might make use of net randoms without receiving IRQs
 | 
					 | 
				
			||||||
	 * to renew them often enough. Let's update the net_rand_state from a
 | 
					 | 
				
			||||||
	 * non-constant value that's not affine to the number of calls to make
 | 
					 | 
				
			||||||
	 * sure it's updated when there's some activity (we don't care in idle).
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	this_cpu_add(net_rand_state.s1, rol32(jiffies, 24) + user_tick);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										464
									
								
								lib/random32.c
									
									
									
									
									
								
							
							
						
						
									
										464
									
								
								lib/random32.c
									
									
									
									
									
								
							| 
						 | 
					@ -41,16 +41,6 @@
 | 
				
			||||||
#include <asm/unaligned.h>
 | 
					#include <asm/unaligned.h>
 | 
				
			||||||
#include <trace/events/random.h>
 | 
					#include <trace/events/random.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_RANDOM32_SELFTEST
 | 
					 | 
				
			||||||
static void __init prandom_state_selftest(void);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
static inline void prandom_state_selftest(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEFINE_PER_CPU(struct rnd_state, net_rand_state)  __latent_entropy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 *	prandom_u32_state - seeded pseudo-random number generator.
 | 
					 *	prandom_u32_state - seeded pseudo-random number generator.
 | 
				
			||||||
 *	@state: pointer to state structure holding seeded state.
 | 
					 *	@state: pointer to state structure holding seeded state.
 | 
				
			||||||
| 
						 | 
					@ -70,26 +60,6 @@ u32 prandom_u32_state(struct rnd_state *state)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(prandom_u32_state);
 | 
					EXPORT_SYMBOL(prandom_u32_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 *	prandom_u32 - pseudo random number generator
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *	A 32 bit pseudo-random number is generated using a fast
 | 
					 | 
				
			||||||
 *	algorithm suitable for simulation. This algorithm is NOT
 | 
					 | 
				
			||||||
 *	considered safe for cryptographic use.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
u32 prandom_u32(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct rnd_state *state = &get_cpu_var(net_rand_state);
 | 
					 | 
				
			||||||
	u32 res;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	res = prandom_u32_state(state);
 | 
					 | 
				
			||||||
	trace_prandom_u32(res);
 | 
					 | 
				
			||||||
	put_cpu_var(net_rand_state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
EXPORT_SYMBOL(prandom_u32);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 *	prandom_bytes_state - get the requested number of pseudo-random bytes
 | 
					 *	prandom_bytes_state - get the requested number of pseudo-random bytes
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -121,20 +91,6 @@ void prandom_bytes_state(struct rnd_state *state, void *buf, size_t bytes)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(prandom_bytes_state);
 | 
					EXPORT_SYMBOL(prandom_bytes_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 *	prandom_bytes - get the requested number of pseudo-random bytes
 | 
					 | 
				
			||||||
 *	@buf: where to copy the pseudo-random bytes to
 | 
					 | 
				
			||||||
 *	@bytes: the requested number of bytes
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void prandom_bytes(void *buf, size_t bytes)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct rnd_state *state = &get_cpu_var(net_rand_state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	prandom_bytes_state(state, buf, bytes);
 | 
					 | 
				
			||||||
	put_cpu_var(net_rand_state);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
EXPORT_SYMBOL(prandom_bytes);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void prandom_warmup(struct rnd_state *state)
 | 
					static void prandom_warmup(struct rnd_state *state)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Calling RNG ten times to satisfy recurrence condition */
 | 
						/* Calling RNG ten times to satisfy recurrence condition */
 | 
				
			||||||
| 
						 | 
					@ -150,96 +106,6 @@ static void prandom_warmup(struct rnd_state *state)
 | 
				
			||||||
	prandom_u32_state(state);
 | 
						prandom_u32_state(state);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static u32 __extract_hwseed(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned int val = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	(void)(arch_get_random_seed_int(&val) ||
 | 
					 | 
				
			||||||
	       arch_get_random_int(&val));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return val;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void prandom_seed_early(struct rnd_state *state, u32 seed,
 | 
					 | 
				
			||||||
			       bool mix_with_hwseed)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
#define LCG(x)	 ((x) * 69069U)	/* super-duper LCG */
 | 
					 | 
				
			||||||
#define HWSEED() (mix_with_hwseed ? __extract_hwseed() : 0)
 | 
					 | 
				
			||||||
	state->s1 = __seed(HWSEED() ^ LCG(seed),        2U);
 | 
					 | 
				
			||||||
	state->s2 = __seed(HWSEED() ^ LCG(state->s1),   8U);
 | 
					 | 
				
			||||||
	state->s3 = __seed(HWSEED() ^ LCG(state->s2),  16U);
 | 
					 | 
				
			||||||
	state->s4 = __seed(HWSEED() ^ LCG(state->s3), 128U);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 *	prandom_seed - add entropy to pseudo random number generator
 | 
					 | 
				
			||||||
 *	@entropy: entropy value
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *	Add some additional entropy to the prandom pool.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void prandom_seed(u32 entropy)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * No locking on the CPUs, but then somewhat random results are, well,
 | 
					 | 
				
			||||||
	 * expected.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	for_each_possible_cpu(i) {
 | 
					 | 
				
			||||||
		struct rnd_state *state = &per_cpu(net_rand_state, i);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		state->s1 = __seed(state->s1 ^ entropy, 2U);
 | 
					 | 
				
			||||||
		prandom_warmup(state);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
EXPORT_SYMBOL(prandom_seed);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 *	Generate some initially weak seeding values to allow
 | 
					 | 
				
			||||||
 *	to start the prandom_u32() engine.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int __init prandom_init(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	prandom_state_selftest();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for_each_possible_cpu(i) {
 | 
					 | 
				
			||||||
		struct rnd_state *state = &per_cpu(net_rand_state, i);
 | 
					 | 
				
			||||||
		u32 weak_seed = (i + jiffies) ^ random_get_entropy();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		prandom_seed_early(state, weak_seed, true);
 | 
					 | 
				
			||||||
		prandom_warmup(state);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
core_initcall(prandom_init);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void __prandom_timer(struct timer_list *unused);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static DEFINE_TIMER(seed_timer, __prandom_timer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void __prandom_timer(struct timer_list *unused)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	u32 entropy;
 | 
					 | 
				
			||||||
	unsigned long expires;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	get_random_bytes(&entropy, sizeof(entropy));
 | 
					 | 
				
			||||||
	prandom_seed(entropy);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* reseed every ~60 seconds, in [40 .. 80) interval with slack */
 | 
					 | 
				
			||||||
	expires = 40 + prandom_u32_max(40);
 | 
					 | 
				
			||||||
	seed_timer.expires = jiffies + msecs_to_jiffies(expires * MSEC_PER_SEC);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	add_timer(&seed_timer);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void __init __prandom_start_seed_timer(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	seed_timer.expires = jiffies + msecs_to_jiffies(40 * MSEC_PER_SEC);
 | 
					 | 
				
			||||||
	add_timer(&seed_timer);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state)
 | 
					void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
| 
						 | 
					@ -259,51 +125,6 @@ void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(prandom_seed_full_state);
 | 
					EXPORT_SYMBOL(prandom_seed_full_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 *	Generate better values after random number generator
 | 
					 | 
				
			||||||
 *	is fully initialized.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void __prandom_reseed(bool late)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned long flags;
 | 
					 | 
				
			||||||
	static bool latch = false;
 | 
					 | 
				
			||||||
	static DEFINE_SPINLOCK(lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Asking for random bytes might result in bytes getting
 | 
					 | 
				
			||||||
	 * moved into the nonblocking pool and thus marking it
 | 
					 | 
				
			||||||
	 * as initialized. In this case we would double back into
 | 
					 | 
				
			||||||
	 * this function and attempt to do a late reseed.
 | 
					 | 
				
			||||||
	 * Ignore the pointless attempt to reseed again if we're
 | 
					 | 
				
			||||||
	 * already waiting for bytes when the nonblocking pool
 | 
					 | 
				
			||||||
	 * got initialized.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* only allow initial seeding (late == false) once */
 | 
					 | 
				
			||||||
	if (!spin_trylock_irqsave(&lock, flags))
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (latch && !late)
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	latch = true;
 | 
					 | 
				
			||||||
	prandom_seed_full_state(&net_rand_state);
 | 
					 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	spin_unlock_irqrestore(&lock, flags);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void prandom_reseed_late(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	__prandom_reseed(true);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int __init prandom_reseed(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	__prandom_reseed(false);
 | 
					 | 
				
			||||||
	__prandom_start_seed_timer();
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
late_initcall(prandom_reseed);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_RANDOM32_SELFTEST
 | 
					#ifdef CONFIG_RANDOM32_SELFTEST
 | 
				
			||||||
static struct prandom_test1 {
 | 
					static struct prandom_test1 {
 | 
				
			||||||
	u32 seed;
 | 
						u32 seed;
 | 
				
			||||||
| 
						 | 
					@ -423,7 +244,28 @@ static struct prandom_test2 {
 | 
				
			||||||
	{  407983964U, 921U,  728767059U },
 | 
						{  407983964U, 921U,  728767059U },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __init prandom_state_selftest(void)
 | 
					static u32 __extract_hwseed(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int val = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(void)(arch_get_random_seed_int(&val) ||
 | 
				
			||||||
 | 
						       arch_get_random_int(&val));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return val;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void prandom_seed_early(struct rnd_state *state, u32 seed,
 | 
				
			||||||
 | 
								       bool mix_with_hwseed)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#define LCG(x)	 ((x) * 69069U)	/* super-duper LCG */
 | 
				
			||||||
 | 
					#define HWSEED() (mix_with_hwseed ? __extract_hwseed() : 0)
 | 
				
			||||||
 | 
						state->s1 = __seed(HWSEED() ^ LCG(seed),        2U);
 | 
				
			||||||
 | 
						state->s2 = __seed(HWSEED() ^ LCG(state->s1),   8U);
 | 
				
			||||||
 | 
						state->s3 = __seed(HWSEED() ^ LCG(state->s2),  16U);
 | 
				
			||||||
 | 
						state->s4 = __seed(HWSEED() ^ LCG(state->s3), 128U);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int __init prandom_state_selftest(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i, j, errors = 0, runs = 0;
 | 
						int i, j, errors = 0, runs = 0;
 | 
				
			||||||
	bool error = false;
 | 
						bool error = false;
 | 
				
			||||||
| 
						 | 
					@ -463,5 +305,267 @@ static void __init prandom_state_selftest(void)
 | 
				
			||||||
		pr_warn("prandom: %d/%d self tests failed\n", errors, runs);
 | 
							pr_warn("prandom: %d/%d self tests failed\n", errors, runs);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		pr_info("prandom: %d self tests passed\n", runs);
 | 
							pr_info("prandom: %d self tests passed\n", runs);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					core_initcall(prandom_state_selftest);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The prandom_u32() implementation is now completely separate from the
 | 
				
			||||||
 | 
					 * prandom_state() functions, which are retained (for now) for compatibility.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Because of (ab)use in the networking code for choosing random TCP/UDP port
 | 
				
			||||||
 | 
					 * numbers, which open DoS possibilities if guessable, we want something
 | 
				
			||||||
 | 
					 * stronger than a standard PRNG.  But the performance requirements of
 | 
				
			||||||
 | 
					 * the network code do not allow robust crypto for this application.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * So this is a homebrew Junior Spaceman implementation, based on the
 | 
				
			||||||
 | 
					 * lowest-latency trustworthy crypto primitive available, SipHash.
 | 
				
			||||||
 | 
					 * (The authors of SipHash have not been consulted about this abuse of
 | 
				
			||||||
 | 
					 * their work.)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Standard SipHash-2-4 uses 2n+4 rounds to hash n words of input to
 | 
				
			||||||
 | 
					 * one word of output.  This abbreviated version uses 2 rounds per word
 | 
				
			||||||
 | 
					 * of output.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct siprand_state {
 | 
				
			||||||
 | 
						unsigned long v0;
 | 
				
			||||||
 | 
						unsigned long v1;
 | 
				
			||||||
 | 
						unsigned long v2;
 | 
				
			||||||
 | 
						unsigned long v3;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DEFINE_PER_CPU(struct siprand_state, net_rand_state) __latent_entropy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This is the core CPRNG function.  As "pseudorandom", this is not used
 | 
				
			||||||
 | 
					 * for truly valuable things, just intended to be a PITA to guess.
 | 
				
			||||||
 | 
					 * For maximum speed, we do just two SipHash rounds per word.  This is
 | 
				
			||||||
 | 
					 * the same rate as 4 rounds per 64 bits that SipHash normally uses,
 | 
				
			||||||
 | 
					 * so hopefully it's reasonably secure.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * There are two changes from the official SipHash finalization:
 | 
				
			||||||
 | 
					 * - We omit some constants XORed with v2 in the SipHash spec as irrelevant;
 | 
				
			||||||
 | 
					 *   they are there only to make the output rounds distinct from the input
 | 
				
			||||||
 | 
					 *   rounds, and this application has no input rounds.
 | 
				
			||||||
 | 
					 * - Rather than returning v0^v1^v2^v3, return v1+v3.
 | 
				
			||||||
 | 
					 *   If you look at the SipHash round, the last operation on v3 is
 | 
				
			||||||
 | 
					 *   "v3 ^= v0", so "v0 ^ v3" just undoes that, a waste of time.
 | 
				
			||||||
 | 
					 *   Likewise "v1 ^= v2".  (The rotate of v2 makes a difference, but
 | 
				
			||||||
 | 
					 *   it still cancels out half of the bits in v2 for no benefit.)
 | 
				
			||||||
 | 
					 *   Second, since the last combining operation was xor, continue the
 | 
				
			||||||
 | 
					 *   pattern of alternating xor/add for a tiny bit of extra non-linearity.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline u32 siprand_u32(struct siprand_state *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long v0 = s->v0, v1 = s->v1, v2 = s->v2, v3 = s->v3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						PRND_SIPROUND(v0, v1, v2, v3);
 | 
				
			||||||
 | 
						PRND_SIPROUND(v0, v1, v2, v3);
 | 
				
			||||||
 | 
						s->v0 = v0;  s->v1 = v1;  s->v2 = v2;  s->v3 = v3;
 | 
				
			||||||
 | 
						return v1 + v3;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *	prandom_u32 - pseudo random number generator
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	A 32 bit pseudo-random number is generated using a fast
 | 
				
			||||||
 | 
					 *	algorithm suitable for simulation. This algorithm is NOT
 | 
				
			||||||
 | 
					 *	considered safe for cryptographic use.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					u32 prandom_u32(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct siprand_state *state = get_cpu_ptr(&net_rand_state);
 | 
				
			||||||
 | 
						u32 res = siprand_u32(state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						trace_prandom_u32(res);
 | 
				
			||||||
 | 
						put_cpu_ptr(&net_rand_state);
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(prandom_u32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *	prandom_bytes - get the requested number of pseudo-random bytes
 | 
				
			||||||
 | 
					 *	@buf: where to copy the pseudo-random bytes to
 | 
				
			||||||
 | 
					 *	@bytes: the requested number of bytes
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void prandom_bytes(void *buf, size_t bytes)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct siprand_state *state = get_cpu_ptr(&net_rand_state);
 | 
				
			||||||
 | 
						u8 *ptr = buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (bytes >= sizeof(u32)) {
 | 
				
			||||||
 | 
							put_unaligned(siprand_u32(state), (u32 *)ptr);
 | 
				
			||||||
 | 
							ptr += sizeof(u32);
 | 
				
			||||||
 | 
							bytes -= sizeof(u32);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bytes > 0) {
 | 
				
			||||||
 | 
							u32 rem = siprand_u32(state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							do {
 | 
				
			||||||
 | 
								*ptr++ = (u8)rem;
 | 
				
			||||||
 | 
								rem >>= BITS_PER_BYTE;
 | 
				
			||||||
 | 
							} while (--bytes > 0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						put_cpu_ptr(&net_rand_state);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(prandom_bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *	prandom_seed - add entropy to pseudo random number generator
 | 
				
			||||||
 | 
					 *	@entropy: entropy value
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	Add some additional seed material to the prandom pool.
 | 
				
			||||||
 | 
					 *	The "entropy" is actually our IP address (the only caller is
 | 
				
			||||||
 | 
					 *	the network code), not for unpredictability, but to ensure that
 | 
				
			||||||
 | 
					 *	different machines are initialized differently.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void prandom_seed(u32 entropy)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						add_device_randomness(&entropy, sizeof(entropy));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for_each_possible_cpu(i) {
 | 
				
			||||||
 | 
							struct siprand_state *state = per_cpu_ptr(&net_rand_state, i);
 | 
				
			||||||
 | 
							unsigned long v0 = state->v0, v1 = state->v1;
 | 
				
			||||||
 | 
							unsigned long v2 = state->v2, v3 = state->v3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							do {
 | 
				
			||||||
 | 
								v3 ^= entropy;
 | 
				
			||||||
 | 
								PRND_SIPROUND(v0, v1, v2, v3);
 | 
				
			||||||
 | 
								PRND_SIPROUND(v0, v1, v2, v3);
 | 
				
			||||||
 | 
								v0 ^= entropy;
 | 
				
			||||||
 | 
							} while (unlikely(!v0 || !v1 || !v2 || !v3));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							WRITE_ONCE(state->v0, v0);
 | 
				
			||||||
 | 
							WRITE_ONCE(state->v1, v1);
 | 
				
			||||||
 | 
							WRITE_ONCE(state->v2, v2);
 | 
				
			||||||
 | 
							WRITE_ONCE(state->v3, v3);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(prandom_seed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *	Generate some initially weak seeding values to allow
 | 
				
			||||||
 | 
					 *	the prandom_u32() engine to be started.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int __init prandom_init_early(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						unsigned long v0, v1, v2, v3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!arch_get_random_long(&v0))
 | 
				
			||||||
 | 
							v0 = jiffies;
 | 
				
			||||||
 | 
						if (!arch_get_random_long(&v1))
 | 
				
			||||||
 | 
							v1 = random_get_entropy();
 | 
				
			||||||
 | 
						v2 = v0 ^ PRND_K0;
 | 
				
			||||||
 | 
						v3 = v1 ^ PRND_K1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for_each_possible_cpu(i) {
 | 
				
			||||||
 | 
							struct siprand_state *state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							v3 ^= i;
 | 
				
			||||||
 | 
							PRND_SIPROUND(v0, v1, v2, v3);
 | 
				
			||||||
 | 
							PRND_SIPROUND(v0, v1, v2, v3);
 | 
				
			||||||
 | 
							v0 ^= i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							state = per_cpu_ptr(&net_rand_state, i);
 | 
				
			||||||
 | 
							state->v0 = v0;  state->v1 = v1;
 | 
				
			||||||
 | 
							state->v2 = v2;  state->v3 = v3;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					core_initcall(prandom_init_early);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Stronger reseeding when available, and periodically thereafter. */
 | 
				
			||||||
 | 
					static void prandom_reseed(struct timer_list *unused);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DEFINE_TIMER(seed_timer, prandom_reseed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void prandom_reseed(struct timer_list *unused)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long expires;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Reinitialize each CPU's PRNG with 128 bits of key.
 | 
				
			||||||
 | 
						 * No locking on the CPUs, but then somewhat random results are,
 | 
				
			||||||
 | 
						 * well, expected.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						for_each_possible_cpu(i) {
 | 
				
			||||||
 | 
							struct siprand_state *state;
 | 
				
			||||||
 | 
							unsigned long v0 = get_random_long(), v2 = v0 ^ PRND_K0;
 | 
				
			||||||
 | 
							unsigned long v1 = get_random_long(), v3 = v1 ^ PRND_K1;
 | 
				
			||||||
 | 
					#if BITS_PER_LONG == 32
 | 
				
			||||||
 | 
							int j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * On 32-bit machines, hash in two extra words to
 | 
				
			||||||
 | 
							 * approximate 128-bit key length.  Not that the hash
 | 
				
			||||||
 | 
							 * has that much security, but this prevents a trivial
 | 
				
			||||||
 | 
							 * 64-bit brute force.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							for (j = 0; j < 2; j++) {
 | 
				
			||||||
 | 
								unsigned long m = get_random_long();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								v3 ^= m;
 | 
				
			||||||
 | 
								PRND_SIPROUND(v0, v1, v2, v3);
 | 
				
			||||||
 | 
								PRND_SIPROUND(v0, v1, v2, v3);
 | 
				
			||||||
 | 
								v0 ^= m;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Probably impossible in practice, but there is a
 | 
				
			||||||
 | 
							 * theoretical risk that a race between this reseeding
 | 
				
			||||||
 | 
							 * and the target CPU writing its state back could
 | 
				
			||||||
 | 
							 * create the all-zero SipHash fixed point.
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * To ensure that never happens, ensure the state
 | 
				
			||||||
 | 
							 * we write contains no zero words.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							state = per_cpu_ptr(&net_rand_state, i);
 | 
				
			||||||
 | 
							WRITE_ONCE(state->v0, v0 ? v0 : -1ul);
 | 
				
			||||||
 | 
							WRITE_ONCE(state->v1, v1 ? v1 : -1ul);
 | 
				
			||||||
 | 
							WRITE_ONCE(state->v2, v2 ? v2 : -1ul);
 | 
				
			||||||
 | 
							WRITE_ONCE(state->v3, v3 ? v3 : -1ul);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* reseed every ~60 seconds, in [40 .. 80) interval with slack */
 | 
				
			||||||
 | 
						expires = round_jiffies(jiffies + 40 * HZ + prandom_u32_max(40 * HZ));
 | 
				
			||||||
 | 
						mod_timer(&seed_timer, expires);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The random ready callback can be called from almost any interrupt.
 | 
				
			||||||
 | 
					 * To avoid worrying about whether it's safe to delay that interrupt
 | 
				
			||||||
 | 
					 * long enough to seed all CPUs, just schedule an immediate timer event.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void prandom_timer_start(struct random_ready_callback *unused)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						mod_timer(&seed_timer, jiffies);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Start periodic full reseeding as soon as strong
 | 
				
			||||||
 | 
					 * random numbers are available.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int __init prandom_init_late(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static struct random_ready_callback random_ready = {
 | 
				
			||||||
 | 
							.func = prandom_timer_start
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						int ret = add_random_ready_callback(&random_ready);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret == -EALREADY) {
 | 
				
			||||||
 | 
							prandom_timer_start(&random_ready);
 | 
				
			||||||
 | 
							ret = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					late_initcall(prandom_init_late);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue