forked from mirrors/linux
		
	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); | ||||
| 	add_interrupt_bench(cycles); | ||||
| 	this_cpu_add(net_rand_state.s1, fast_pool->pool[cycles & 3]); | ||||
| 
 | ||||
| 	if (unlikely(crng_init == 0)) { | ||||
| 		if ((fast_pool->count >= 64) && | ||||
|  |  | |||
|  | @ -16,12 +16,44 @@ void prandom_bytes(void *buf, size_t nbytes); | |||
| void prandom_seed(u32 seed); | ||||
| 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 { | ||||
| 	__u32 s1, s2, s3, s4; | ||||
| }; | ||||
| 
 | ||||
| DECLARE_PER_CPU(struct rnd_state, net_rand_state); | ||||
| 
 | ||||
| u32 prandom_u32_state(struct rnd_state *state); | ||||
| void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes); | ||||
| void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state); | ||||
|  |  | |||
|  | @ -1717,13 +1717,6 @@ void update_process_times(int user_tick) | |||
| 	scheduler_tick(); | ||||
| 	if (IS_ENABLED(CONFIG_POSIX_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 <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. | ||||
|  *	@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); | ||||
| 
 | ||||
| /**
 | ||||
|  *	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 | ||||
|  * | ||||
|  | @ -121,20 +91,6 @@ void prandom_bytes_state(struct rnd_state *state, void *buf, size_t bytes) | |||
| } | ||||
| 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) | ||||
| { | ||||
| 	/* Calling RNG ten times to satisfy recurrence condition */ | ||||
|  | @ -150,96 +106,6 @@ static void prandom_warmup(struct rnd_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) | ||||
| { | ||||
| 	int i; | ||||
|  | @ -259,51 +125,6 @@ void prandom_seed_full_state(struct rnd_state __percpu *pcpu_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 | ||||
| static struct prandom_test1 { | ||||
| 	u32 seed; | ||||
|  | @ -423,7 +244,28 @@ static struct prandom_test2 { | |||
| 	{  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; | ||||
| 	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); | ||||
| 	else | ||||
| 		pr_info("prandom: %d self tests passed\n", runs); | ||||
| 	return 0; | ||||
| } | ||||
| core_initcall(prandom_state_selftest); | ||||
| #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
	
	 George Spelvin
						George Spelvin