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 + -
显示快捷键?