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