random.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,115 行 · 第 1/5 页
C
2,115 行
{ unsigned int mask; poll_wait(file, &random_read_wait, wait); poll_wait(file, &random_write_wait, wait); mask = 0; if (random_state->entropy_count >= random_read_wakeup_thresh) mask |= POLLIN | POLLRDNORM; if (random_state->entropy_count < random_write_wakeup_thresh) mask |= POLLOUT | POLLWRNORM; return mask;}static ssize_trandom_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos){ int ret = 0; size_t bytes; __u32 buf[16]; const char __user *p = buffer; size_t c = count; while (c > 0) { bytes = min(c, sizeof(buf)); bytes -= copy_from_user(&buf, p, bytes); if (!bytes) { ret = -EFAULT; break; } c -= bytes; p += bytes; add_entropy_words(random_state, buf, (bytes + 3) / 4); } if (p == buffer) { return (ssize_t)ret; } else { file->f_dentry->d_inode->i_mtime = CURRENT_TIME; mark_inode_dirty(file->f_dentry->d_inode); return (ssize_t)(p - buffer); }}static intrandom_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg){ int size, ent_count; int __user *p = (int __user *)arg; int retval; switch (cmd) { case RNDGETENTCNT: ent_count = random_state->entropy_count; if (put_user(ent_count, p)) return -EFAULT; return 0; case RNDADDTOENTCNT: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (get_user(ent_count, p)) return -EFAULT; credit_entropy_store(random_state, ent_count); /* * Wake up waiting processes if we have enough * entropy. */ if (random_state->entropy_count >= random_read_wakeup_thresh) wake_up_interruptible(&random_read_wait); return 0; case RNDADDENTROPY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (get_user(ent_count, p++)) return -EFAULT; if (ent_count < 0) return -EINVAL; if (get_user(size, p++)) return -EFAULT; retval = random_write(file, (const char __user *) p, size, &file->f_pos); if (retval < 0) return retval; credit_entropy_store(random_state, ent_count); /* * Wake up waiting processes if we have enough * entropy. */ if (random_state->entropy_count >= random_read_wakeup_thresh) wake_up_interruptible(&random_read_wait); return 0; case RNDZAPENTCNT: if (!capable(CAP_SYS_ADMIN)) return -EPERM; random_state->entropy_count = 0; return 0; case RNDCLEARPOOL: /* Clear the entropy pool and associated counters. */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; clear_entropy_store(random_state); init_std_data(random_state); return 0; default: return -EINVAL; }}struct file_operations random_fops = { .read = random_read, .write = random_write, .poll = random_poll, .ioctl = random_ioctl,};struct file_operations urandom_fops = { .read = urandom_read, .write = random_write, .ioctl = random_ioctl,};/*************************************************************** * Random UUID interface * * Used here for a Boot ID, but can be useful for other kernel * drivers. ***************************************************************//* * Generate random UUID */void generate_random_uuid(unsigned char uuid_out[16]){ get_random_bytes(uuid_out, 16); /* Set UUID version to 4 --- truely random generation */ uuid_out[6] = (uuid_out[6] & 0x0F) | 0x40; /* Set the UUID variant to DCE */ uuid_out[8] = (uuid_out[8] & 0x3F) | 0x80;}EXPORT_SYMBOL(generate_random_uuid);/******************************************************************** * * Sysctl interface * ********************************************************************/#ifdef CONFIG_SYSCTL#include <linux/sysctl.h>static int sysctl_poolsize;static int min_read_thresh, max_read_thresh;static int min_write_thresh, max_write_thresh;static char sysctl_bootid[16];/* * This function handles a request from the user to change the pool size * of the primary entropy store. */static int change_poolsize(int poolsize){ struct entropy_store *new_store, *old_store; int ret; if ((ret = create_entropy_store(poolsize, random_state->name, &new_store))) return ret; add_entropy_words(new_store, random_state->pool, random_state->poolinfo.poolwords); credit_entropy_store(new_store, random_state->entropy_count); sysctl_init_random(new_store); old_store = random_state; random_state = batch_work.data = new_store; free_entropy_store(old_store); return 0;}static int proc_do_poolsize(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos){ int ret; sysctl_poolsize = random_state->poolinfo.POOLBYTES; ret = proc_dointvec(table, write, filp, buffer, lenp, ppos); if (ret || !write || (sysctl_poolsize == random_state->poolinfo.POOLBYTES)) return ret; return change_poolsize(sysctl_poolsize);}static int poolsize_strategy(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, void **context){ int len; sysctl_poolsize = random_state->poolinfo.POOLBYTES; /* * We only handle the write case, since the read case gets * handled by the default handler (and we don't care if the * write case happens twice; it's harmless). */ if (newval && newlen) { len = newlen; if (len > table->maxlen) len = table->maxlen; if (copy_from_user(table->data, newval, len)) return -EFAULT; } if (sysctl_poolsize != random_state->poolinfo.POOLBYTES) return change_poolsize(sysctl_poolsize); return 0;}/* * These functions is used to return both the bootid UUID, and random * UUID. The difference is in whether table->data is NULL; if it is, * then a new UUID is generated and returned to the user. * * If the user accesses this via the proc interface, it will be returned * as an ASCII string in the standard UUID format. If accesses via the * sysctl system call, it is returned as 16 bytes of binary data. */static int proc_do_uuid(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos){ ctl_table fake_table; unsigned char buf[64], tmp_uuid[16], *uuid; uuid = table->data; if (!uuid) { uuid = tmp_uuid; uuid[8] = 0; } if (uuid[8] == 0) generate_random_uuid(uuid); sprintf(buf, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" "%02x%02x%02x%02x%02x%02x", uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]); fake_table.data = buf; fake_table.maxlen = sizeof(buf); return proc_dostring(&fake_table, write, filp, buffer, lenp, ppos);}static int uuid_strategy(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, void **context){ unsigned char tmp_uuid[16], *uuid; unsigned int len; if (!oldval || !oldlenp) return 1; uuid = table->data; if (!uuid) { uuid = tmp_uuid; uuid[8] = 0; } if (uuid[8] == 0) generate_random_uuid(uuid); if (get_user(len, oldlenp)) return -EFAULT; if (len) { if (len > 16) len = 16; if (copy_to_user(oldval, uuid, len) || put_user(len, oldlenp)) return -EFAULT; } return 1;}ctl_table random_table[] = { { .ctl_name = RANDOM_POOLSIZE, .procname = "poolsize", .data = &sysctl_poolsize, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_do_poolsize, .strategy = &poolsize_strategy, }, { .ctl_name = RANDOM_ENTROPY_COUNT, .procname = "entropy_avail", .maxlen = sizeof(int), .mode = 0444, .proc_handler = &proc_dointvec, }, { .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 }};static void sysctl_init_random(struct entropy_store *random_state){ min_read_thresh = 8; min_write_thresh = 0; max_read_thresh = max_write_thresh = random_state->poolinfo.POOLBITS; random_table[1].data = &random_state->entropy_count;}#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/* * Basic cut-down MD4 transform. Returns only 32 bits of result. */static __u32 halfMD4Transform (__u32 const buf[4], __u32 const in[8]){ __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 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[0] + K2, 3); ROUND(G, d, a, b, c, in[2] + K2, 5); ROUND(G, c, d, a, b, in[4] + K2, 9); ROUND(G, b, c, d, a, in[6] + K2, 13); /* Round 3 */ ROUND(H
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?