random.c

来自「linux 内核源代码」· C语言 代码 · 共 1,669 行 · 第 1/4 页

C
1,669
字号
		.ctl_name	= RANDOM_ENTROPY_COUNT,		.procname	= "entropy_avail",		.maxlen		= sizeof(int),		.mode		= 0444,		.proc_handler	= &proc_dointvec,		.data		= &input_pool.entropy_count,	},	{		.ctl_name	= RANDOM_READ_THRESH,		.procname	= "read_wakeup_threshold",		.data		= &random_read_wakeup_thresh,		.maxlen		= sizeof(int),		.mode		= 0644,		.proc_handler	= &proc_dointvec_minmax,		.strategy	= &sysctl_intvec,		.extra1		= &min_read_thresh,		.extra2		= &max_read_thresh,	},	{		.ctl_name	= RANDOM_WRITE_THRESH,		.procname	= "write_wakeup_threshold",		.data		= &random_write_wakeup_thresh,		.maxlen		= sizeof(int),		.mode		= 0644,		.proc_handler	= &proc_dointvec_minmax,		.strategy	= &sysctl_intvec,		.extra1		= &min_write_thresh,		.extra2		= &max_write_thresh,	},	{		.ctl_name	= RANDOM_BOOT_ID,		.procname	= "boot_id",		.data		= &sysctl_bootid,		.maxlen		= 16,		.mode		= 0444,		.proc_handler	= &proc_do_uuid,		.strategy	= &uuid_strategy,	},	{		.ctl_name	= RANDOM_UUID,		.procname	= "uuid",		.maxlen		= 16,		.mode		= 0444,		.proc_handler	= &proc_do_uuid,		.strategy	= &uuid_strategy,	},	{ .ctl_name = 0 }};#endif 	/* CONFIG_SYSCTL *//******************************************************************** * * Random funtions for networking * ********************************************************************//* * TCP initial sequence number picking.  This uses the random number * generator to pick an initial secret value.  This value is hashed * along with the TCP endpoint information to provide a unique * starting point for each pair of TCP endpoints.  This defeats * attacks which rely on guessing the initial TCP sequence number. * This algorithm was suggested by Steve Bellovin. * * Using a very strong hash was taking an appreciable amount of the total * TCP connection establishment time, so this is a weaker hash, * compensated for by changing the secret periodically. *//* F, G and H are basic MD4 functions: selection, majority, parity */#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))#define H(x, y, z) ((x) ^ (y) ^ (z))/* * The generic round function.  The application is so specific that * we don't bother protecting all the arguments with parens, as is generally * good macro practice, in favor of extra legibility. * Rotation is separate from addition to prevent recomputation */#define ROUND(f, a, b, c, d, x, s)	\	(a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s)))#define K1 0#define K2 013240474631UL#define K3 015666365641UL#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12]){	__u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];	/* Round 1 */	ROUND(F, a, b, c, d, in[ 0] + K1,  3);	ROUND(F, d, a, b, c, in[ 1] + K1,  7);	ROUND(F, c, d, a, b, in[ 2] + K1, 11);	ROUND(F, b, c, d, a, in[ 3] + K1, 19);	ROUND(F, a, b, c, d, in[ 4] + K1,  3);	ROUND(F, d, a, b, c, in[ 5] + K1,  7);	ROUND(F, c, d, a, b, in[ 6] + K1, 11);	ROUND(F, b, c, d, a, in[ 7] + K1, 19);	ROUND(F, a, b, c, d, in[ 8] + K1,  3);	ROUND(F, d, a, b, c, in[ 9] + K1,  7);	ROUND(F, c, d, a, b, in[10] + K1, 11);	ROUND(F, b, c, d, a, in[11] + K1, 19);	/* Round 2 */	ROUND(G, a, b, c, d, in[ 1] + K2,  3);	ROUND(G, d, a, b, c, in[ 3] + K2,  5);	ROUND(G, c, d, a, b, in[ 5] + K2,  9);	ROUND(G, b, c, d, a, in[ 7] + K2, 13);	ROUND(G, a, b, c, d, in[ 9] + K2,  3);	ROUND(G, d, a, b, c, in[11] + K2,  5);	ROUND(G, c, d, a, b, in[ 0] + K2,  9);	ROUND(G, b, c, d, a, in[ 2] + K2, 13);	ROUND(G, a, b, c, d, in[ 4] + K2,  3);	ROUND(G, d, a, b, c, in[ 6] + K2,  5);	ROUND(G, c, d, a, b, in[ 8] + K2,  9);	ROUND(G, b, c, d, a, in[10] + K2, 13);	/* Round 3 */	ROUND(H, a, b, c, d, in[ 3] + K3,  3);	ROUND(H, d, a, b, c, in[ 7] + K3,  9);	ROUND(H, c, d, a, b, in[11] + K3, 11);	ROUND(H, b, c, d, a, in[ 2] + K3, 15);	ROUND(H, a, b, c, d, in[ 6] + K3,  3);	ROUND(H, d, a, b, c, in[10] + K3,  9);	ROUND(H, c, d, a, b, in[ 1] + K3, 11);	ROUND(H, b, c, d, a, in[ 5] + K3, 15);	ROUND(H, a, b, c, d, in[ 9] + K3,  3);	ROUND(H, d, a, b, c, in[ 0] + K3,  9);	ROUND(H, c, d, a, b, in[ 4] + K3, 11);	ROUND(H, b, c, d, a, in[ 8] + K3, 15);	return buf[1] + b; /* "most hashed" word */	/* Alternative: return sum of all words? */}#endif#undef ROUND#undef F#undef G#undef H#undef K1#undef K2#undef K3/* This should not be decreased so low that ISNs wrap too fast. */#define REKEY_INTERVAL (300 * HZ)/* * Bit layout of the tcp sequence numbers (before adding current time): * bit 24-31: increased after every key exchange * bit 0-23: hash(source,dest) * * The implementation is similar to the algorithm described * in the Appendix of RFC 1185, except that * - it uses a 1 MHz clock instead of a 250 kHz clock * - it performs a rekey every 5 minutes, which is equivalent * 	to a (source,dest) tulple dependent forward jump of the * 	clock by 0..2^(HASH_BITS+1) * * Thus the average ISN wraparound time is 68 minutes instead of * 4.55 hours. * * SMP cleanup and lock avoidance with poor man's RCU. * 			Manfred Spraul <manfred@colorfullife.com> * */#define COUNT_BITS 8#define COUNT_MASK ((1 << COUNT_BITS) - 1)#define HASH_BITS 24#define HASH_MASK ((1 << HASH_BITS) - 1)static struct keydata {	__u32 count; /* already shifted to the final position */	__u32 secret[12];} ____cacheline_aligned ip_keydata[2];static unsigned int ip_cnt;static void rekey_seq_generator(struct work_struct *work);static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator);/* * Lock avoidance: * The ISN generation runs lockless - it's just a hash over random data. * State changes happen every 5 minutes when the random key is replaced. * Synchronization is performed by having two copies of the hash function * state and rekey_seq_generator always updates the inactive copy. * The copy is then activated by updating ip_cnt. * The implementation breaks down if someone blocks the thread * that processes SYN requests for more than 5 minutes. Should never * happen, and even if that happens only a not perfectly compliant * ISN is generated, nothing fatal. */static void rekey_seq_generator(struct work_struct *work){	struct keydata *keyptr = &ip_keydata[1 ^ (ip_cnt & 1)];	get_random_bytes(keyptr->secret, sizeof(keyptr->secret));	keyptr->count = (ip_cnt & COUNT_MASK) << HASH_BITS;	smp_wmb();	ip_cnt++;	schedule_delayed_work(&rekey_work, REKEY_INTERVAL);}static inline struct keydata *get_keyptr(void){	struct keydata *keyptr = &ip_keydata[ip_cnt & 1];	smp_rmb();	return keyptr;}static __init int seqgen_init(void){	rekey_seq_generator(NULL);	return 0;}late_initcall(seqgen_init);#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)__u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,				   __be16 sport, __be16 dport){	__u32 seq;	__u32 hash[12];	struct keydata *keyptr = get_keyptr();	/* The procedure is the same as for IPv4, but addresses are longer.	 * Thus we must use twothirdsMD4Transform.	 */	memcpy(hash, saddr, 16);	hash[4]=((__force u16)sport << 16) + (__force u16)dport;	memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7);	seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK;	seq += keyptr->count;	seq += ktime_to_ns(ktime_get_real());	return seq;}EXPORT_SYMBOL(secure_tcpv6_sequence_number);#endif/*  The code below is shamelessly stolen from secure_tcp_sequence_number(). *  All blames to Andrey V. Savochkin <saw@msu.ru>. */__u32 secure_ip_id(__be32 daddr){	struct keydata *keyptr;	__u32 hash[4];	keyptr = get_keyptr();	/*	 *  Pick a unique starting offset for each IP destination.	 *  The dest ip address is placed in the starting vector,	 *  which is then hashed with random data.	 */	hash[0] = (__force __u32)daddr;	hash[1] = keyptr->secret[9];	hash[2] = keyptr->secret[10];	hash[3] = keyptr->secret[11];	return half_md4_transform(hash, keyptr->secret);}#ifdef CONFIG_INET__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,				 __be16 sport, __be16 dport){	__u32 seq;	__u32 hash[4];	struct keydata *keyptr = get_keyptr();	/*	 *  Pick a unique starting offset for each TCP connection endpoints	 *  (saddr, daddr, sport, dport).	 *  Note that the words are placed into the starting vector, which is	 *  then mixed with a partial MD4 over random data.	 */	hash[0]=(__force u32)saddr;	hash[1]=(__force u32)daddr;	hash[2]=((__force u16)sport << 16) + (__force u16)dport;	hash[3]=keyptr->secret[11];	seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK;	seq += keyptr->count;	/*	 *	As close as possible to RFC 793, which	 *	suggests using a 250 kHz clock.	 *	Further reading shows this assumes 2 Mb/s networks.	 *	For 10 Mb/s Ethernet, a 1 MHz clock is appropriate.	 *	For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but	 *	we also need to limit the resolution so that the u32 seq	 *	overlaps less than one time per MSL (2 minutes).	 *	Choosing a clock of 64 ns period is OK. (period of 274 s)	 */	seq += ktime_to_ns(ktime_get_real()) >> 6;#if 0	printk("init_seq(%lx, %lx, %d, %d) = %d\n",	       saddr, daddr, sport, dport, seq);#endif	return seq;}/* Generate secure starting point for ephemeral IPV4 transport port search */u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport){	struct keydata *keyptr = get_keyptr();	u32 hash[4];	/*	 *  Pick a unique starting offset for each ephemeral port search	 *  (saddr, daddr, dport) and 48bits of random data.	 */	hash[0] = (__force u32)saddr;	hash[1] = (__force u32)daddr;	hash[2] = (__force u32)dport ^ keyptr->secret[10];	hash[3] = keyptr->secret[11];	return half_md4_transform(hash, keyptr->secret);}#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport){	struct keydata *keyptr = get_keyptr();	u32 hash[12];	memcpy(hash, saddr, 16);	hash[4] = (__force u32)dport;	memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7);	return twothirdsMD4Transform((const __u32 *)daddr, hash);}#endif#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)/* Similar to secure_tcp_sequence_number but generate a 48 bit value * bit's 32-47 increase every key exchange *       0-31  hash(source, dest) */u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,				__be16 sport, __be16 dport){	u64 seq;	__u32 hash[4];	struct keydata *keyptr = get_keyptr();	hash[0] = (__force u32)saddr;	hash[1] = (__force u32)daddr;	hash[2] = ((__force u16)sport << 16) + (__force u16)dport;	hash[3] = keyptr->secret[11];	seq = half_md4_transform(hash, keyptr->secret);	seq |= ((u64)keyptr->count) << (32 - HASH_BITS);	seq += ktime_to_ns(ktime_get_real());	seq &= (1ull << 48) - 1;#if 0	printk("dccp init_seq(%lx, %lx, %d, %d) = %d\n",	       saddr, daddr, sport, dport, seq);#endif	return seq;}EXPORT_SYMBOL(secure_dccp_sequence_number);#endif#endif /* CONFIG_INET *//* * Get a random word for internal kernel use only. Similar to urandom but * with the goal of minimal entropy pool depletion. As a result, the random * value is not cryptographically secure but for several uses the cost of * depleting entropy is too high */unsigned int get_random_int(void){	/*	 * Use IP's RNG. It suits our purpose perfectly: it re-keys itself	 * every second, from the entropy pool (and thus creates a limited	 * drain on it), and uses halfMD4Transform within the second. We	 * also mix it with jiffies and the PID:	 */	return secure_ip_id((__force __be32)(current->pid + jiffies));}/* * randomize_range() returns a start address such that * *    [...... <range> .....] *  start                  end * * a <range> with size "len" starting at the return value is inside in the * area defined by [start, end], but is otherwise randomized. */unsigned longrandomize_range(unsigned long start, unsigned long end, unsigned long len){	unsigned long range = end - len - start;	if (end <= start + len)		return 0;	return PAGE_ALIGN(get_random_int() % range + start);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?