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