random.c
来自「linux 内核源代码」· C语言 代码 · 共 1,669 行 · 第 1/4 页
C
1,669 行
xfer_secondary_pool(r, nbytes); nbytes = account(r, nbytes, 0, 0); while (nbytes) { if (need_resched()) { if (signal_pending(current)) { if (ret == 0) ret = -ERESTARTSYS; break; } schedule(); } extract_buf(r, tmp); i = min_t(int, nbytes, EXTRACT_SIZE); if (copy_to_user(buf, tmp, i)) { ret = -EFAULT; break; } nbytes -= i; buf += i; ret += i; } /* Wipe data just returned from memory */ memset(tmp, 0, sizeof(tmp)); return ret;}/* * This function is the exported kernel interface. It returns some * number of good random numbers, suitable for seeding TCP sequence * numbers, etc. */void get_random_bytes(void *buf, int nbytes){ extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0);}EXPORT_SYMBOL(get_random_bytes);/* * init_std_data - initialize pool with system data * * @r: pool to initialize * * This function clears the pool's entropy count and mixes some system * data into the pool to prepare it for use. The pool is not cleared * as that can only decrease the entropy in the pool. */static void init_std_data(struct entropy_store *r){ ktime_t now; unsigned long flags; spin_lock_irqsave(&r->lock, flags); r->entropy_count = 0; spin_unlock_irqrestore(&r->lock, flags); now = ktime_get_real(); add_entropy_words(r, (__u32 *)&now, sizeof(now)/4); add_entropy_words(r, (__u32 *)utsname(), sizeof(*(utsname()))/4);}static int __init rand_initialize(void){ init_std_data(&input_pool); init_std_data(&blocking_pool); init_std_data(&nonblocking_pool); return 0;}module_init(rand_initialize);void rand_initialize_irq(int irq){ struct timer_rand_state *state; if (irq >= NR_IRQS || irq_timer_state[irq]) return; /* * If kzalloc returns null, we just won't use that entropy * source. */ state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); if (state) irq_timer_state[irq] = state;}#ifdef CONFIG_BLOCKvoid rand_initialize_disk(struct gendisk *disk){ struct timer_rand_state *state; /* * If kzalloc returns null, we just won't use that entropy * source. */ state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); if (state) disk->random = state;}#endifstatic ssize_trandom_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos){ ssize_t n, retval = 0, count = 0; if (nbytes == 0) return 0; while (nbytes > 0) { n = nbytes; if (n > SEC_XFER_SIZE) n = SEC_XFER_SIZE; DEBUG_ENT("reading %d bits\n", n*8); n = extract_entropy_user(&blocking_pool, buf, n); DEBUG_ENT("read got %d bits (%d still needed)\n", n*8, (nbytes-n)*8); if (n == 0) { if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; break; } DEBUG_ENT("sleeping?\n"); wait_event_interruptible(random_read_wait, input_pool.entropy_count >= random_read_wakeup_thresh); DEBUG_ENT("awake\n"); if (signal_pending(current)) { retval = -ERESTARTSYS; break; } continue; } if (n < 0) { retval = n; break; } count += n; buf += n; nbytes -= n; break; /* This break makes the device work */ /* like a named pipe */ } /* * If we gave the user some bytes, update the access time. */ if (count) file_accessed(file); return (count ? count : retval);}static ssize_turandom_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos){ return extract_entropy_user(&nonblocking_pool, buf, nbytes);}static unsigned intrandom_poll(struct file *file, poll_table * wait){ unsigned int mask; poll_wait(file, &random_read_wait, wait); poll_wait(file, &random_write_wait, wait); mask = 0; if (input_pool.entropy_count >= random_read_wakeup_thresh) mask |= POLLIN | POLLRDNORM; if (input_pool.entropy_count < random_write_wakeup_thresh) mask |= POLLOUT | POLLWRNORM; return mask;}static intwrite_pool(struct entropy_store *r, const char __user *buffer, size_t count){ size_t bytes; __u32 buf[16]; const char __user *p = buffer; while (count > 0) { bytes = min(count, sizeof(buf)); if (copy_from_user(&buf, p, bytes)) return -EFAULT; count -= bytes; p += bytes; add_entropy_words(r, buf, (bytes + 3) / 4); } return 0;}static ssize_trandom_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos){ size_t ret; struct inode *inode = file->f_path.dentry->d_inode; ret = write_pool(&blocking_pool, buffer, count); if (ret) return ret; ret = write_pool(&nonblocking_pool, buffer, count); if (ret) return ret; inode->i_mtime = current_fs_time(inode->i_sb); mark_inode_dirty(inode); return (ssize_t)count;}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 = input_pool.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(&input_pool, ent_count); /* * Wake up waiting processes if we have enough * entropy. */ if (input_pool.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 = write_pool(&input_pool, (const char __user *)p, size); if (retval < 0) return retval; credit_entropy_store(&input_pool, ent_count); /* * Wake up waiting processes if we have enough * entropy. */ if (input_pool.entropy_count >= random_read_wakeup_thresh) wake_up_interruptible(&random_read_wait); return 0; case RNDZAPENTCNT: case RNDCLEARPOOL: /* Clear the entropy pool counters. */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; init_std_data(&input_pool); init_std_data(&blocking_pool); init_std_data(&nonblocking_pool); return 0; default: return -EINVAL; }}const struct file_operations random_fops = { .read = random_read, .write = random_write, .poll = random_poll, .ioctl = random_ioctl,};const 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 min_read_thresh = 8, min_write_thresh;static int max_read_thresh = INPUT_POOL_WORDS * 32;static int max_write_thresh = INPUT_POOL_WORDS * 32;static char sysctl_bootid[16];/* * 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){ 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;}static int sysctl_poolsize = INPUT_POOL_WORDS * 32;ctl_table random_table[] = { { .ctl_name = RANDOM_POOLSIZE, .procname = "poolsize", .data = &sysctl_poolsize, .maxlen = sizeof(int), .mode = 0444, .proc_handler = &proc_dointvec, }, {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?