cvs commit: patches/linux linux-2.4.26-frandom-2.patch linux-2.6.5-frandom-1.patch

tushar at linuxfromscratch.org tushar at linuxfromscratch.org
Fri May 7 23:01:31 PDT 2004


tushar      04/05/08 00:01:31

  Added:       linux    linux-2.4.26-frandom-2.patch
                        linux-2.6.5-frandom-1.patch
  Log:
  Added linux frandom patches
  
  Revision  Changes    Path
  1.1                  patches/linux/linux-2.4.26-frandom-2.patch
  
  Index: linux-2.4.26-frandom-2.patch
  ===================================================================
  Submitted By: Robert Connolly <robert at linuxfromscratch dot org> (ashes)
  Date: 2004-05-07
  Initial Package Version: Linux 2.4.26
  Origin: http://frandom.sourceforge.net/ - frandom-0.8
  Description: This is usefull for smashing stack protector, wiping
  discs, mktemp, and more.
  This source was modified for 2.4.26, and is enabled by default in
  arch/i386/defconfig
  
  Thanks to Eli Billauer
  http://www.billauer.co.il/
  http://frandom.sourceforge.net/
  
  Also see:
  http://www.linuxfromscratch.org/hlfs/
  http://www.linuxfromscratch.org/hints/downloads/files/entropy.txt
  http://www.linuxfromscratch.org/~robert/hlfs/hints/attachments/entropy/\
  	frandom-0.8.tar.gz
  
  diff -Naur linux-2.4.26.orig/Documentation/Configure.help linux-2.4.26.frandom/Documentation/Configure.help
  --- linux-2.4.26.orig/Documentation/Configure.help	2004-04-14 13:05:24.000000000 +0000
  +++ linux-2.4.26.frandom/Documentation/Configure.help	2004-04-18 21:56:30.000000000 +0000
  @@ -18294,6 +18294,17 @@
     input/output character sets. Say Y here for the UTF-8 encoding of
     the Unicode/ISO9646 universal character set.
   
  +Fast random data generator suite (/dev/frandom and /dev/erandom)
  +CONFIG_FRANDOM
  +  Fast random data/number generator support in kernel. This random
  +  generator is 10-50 times faster than /dev/urandom, and saves kernel
  +  entropy.
  +
  +  If unsure, say Y unless you're tight on kernel size. This module is
  +  small and harmless otherwise.
  +
  +  If you choose M, the sysctl interface will be disabled.
  +
   Virtual terminal
   CONFIG_VT
     If you say Y here, you will get support for terminal devices with
  diff -Naur linux-2.4.26.orig/arch/i386/defconfig linux-2.4.26.frandom/arch/i386/defconfig
  --- linux-2.4.26.orig/arch/i386/defconfig	2004-04-14 13:05:25.000000000 +0000
  +++ linux-2.4.26.frandom/arch/i386/defconfig	2004-04-18 21:57:52.000000000 +0000
  @@ -562,6 +562,7 @@
   #
   CONFIG_VT=y
   CONFIG_VT_CONSOLE=y
  +CONFIG_FRANDOM=y
   CONFIG_SERIAL=y
   # CONFIG_SERIAL_CONSOLE is not set
   # CONFIG_SERIAL_EXTENDED is not set
  diff -Naur linux-2.4.26.orig/drivers/char/Config.in linux-2.4.26.frandom/drivers/char/Config.in
  --- linux-2.4.26.orig/drivers/char/Config.in	2004-02-18 13:36:31.000000000 +0000
  +++ linux-2.4.26.frandom/drivers/char/Config.in	2004-04-18 21:56:30.000000000 +0000
  @@ -25,6 +25,7 @@
         tristate '   Dual serial port support' CONFIG_DUALSP_SERIAL
      fi
   fi
  +tristate 'Fast random data generator suite (/dev/frandom and /dev/erandom)' CONFIG_FRANDOM
   dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL
   if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
      bool '  Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
  diff -Naur linux-2.4.26.orig/drivers/char/Makefile linux-2.4.26.frandom/drivers/char/Makefile
  --- linux-2.4.26.orig/drivers/char/Makefile	2004-02-18 13:36:31.000000000 +0000
  +++ linux-2.4.26.frandom/drivers/char/Makefile	2004-04-18 21:56:30.000000000 +0000
  @@ -25,7 +25,7 @@
   			misc.o pty.o random.o selection.o serial.o \
   			sonypi.o tty_io.o tty_ioctl.o generic_serial.o \
   			au1000_gpio.o vac-serial.o hp_psaux.o nvram.o \
  -			scx200.o fetchop.o
  +			scx200.o fetchop.o frandom.o
   
   mod-subdirs	:=	joystick ftape drm drm-4.0 pcmcia
   
  @@ -334,6 +334,8 @@
     obj-y += ipmi/ipmi.o
   endif
   
  +obj-$(CONFIG_FRANDOM) += frandom.o
  +
   include $(TOPDIR)/Rules.make
   
   fastdep:
  diff -Naur linux-2.4.26.orig/drivers/char/frandom.c linux-2.4.26.frandom/drivers/char/frandom.c
  --- linux-2.4.26.orig/drivers/char/frandom.c	1970-01-01 00:00:00.000000000 +0000
  +++ linux-2.4.26.frandom/drivers/char/frandom.c	2004-04-18 21:56:30.000000000 +0000
  @@ -0,0 +1,362 @@
  +/*
  +** frandom.c
  +**      Fast pseudo-random generator 
  +**
  +**      (c) Copyright 2003 Eli Billauer
  +**      http://www.billauer.co.il
  +**
  +** This program is free software; you can redistribute it and/or modify
  +** it under the terms of the GNU General Public License as published by
  +** the Free Software Foundation; either version 2 of the License, or
  +** (at your option) any later version.
  +**
  +** Usage: mknod /dev/frandom c 235 11
  +**        mknod /dev/erandom c 235 12
  +**        insmod frandom
  +**
  +** This code is highly based upon the examples given in the book "Linux
  +** Device Drivers" by Alessandro Rubini and Jonathan Corbet, published
  +** by O'Reilly & Associates.
  +** O'Reilly's release of this book on the web for free is highly
  +** appreciated.
  +**
  +*/
  +
  +#include <linux/version.h>
  +#include <linux/config.h>
  +#include <linux/module.h>
  +
  +#include <linux/kernel.h>
  +#include <linux/init.h>
  +#include <linux/slab.h> 
  +#include <linux/fs.h> 
  +#include <linux/errno.h>
  +#include <linux/types.h> 
  +#include <linux/random.h>
  +
  +#include <asm/uaccess.h>
  +
  +#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,0))
  +#include <linux/moduleparam.h>
  +#endif
  +
  +#define INTERNAL_SEED 0
  +#define EXTERNAL_SEED 1
  +
  +#define FRANDOM_MAJOR 235
  +#define FRANDOM_MINOR 11 
  +#define ERANDOM_MINOR 12 
  +
  +static struct file_operations frandom_fops; /* Values assigned below */
  +
  +static int erandom_seeded = 0; /* Internal flag */
  +
  +static int frandom_major = FRANDOM_MAJOR;
  +static int frandom_minor = FRANDOM_MINOR;
  +static int erandom_minor = ERANDOM_MINOR;
  +static int frandom_bufsize = 256;
  +static int frandom_chunklimit = 0; /* =0 means unlimited */
  +
  +MODULE_DESCRIPTION("Fast pseudo-random number generator");
  +MODULE_LICENSE("GPL");
  +MODULE_AUTHOR("Eli Billauer");
  +MODULE_PARM(frandom_major,"i");
  +MODULE_PARM_DESC(frandom_major,"Major number of /dev/frandom and /dev/erandom");
  +MODULE_PARM(frandom_minor,"i");
  +MODULE_PARM_DESC(frandom_minor,"Minor number of /dev/frandom");
  +MODULE_PARM(erandom_minor,"i");
  +MODULE_PARM_DESC(erandom_minor,"Minor number of /dev/erandom");
  +MODULE_PARM(frandom_bufsize,"i");
  +MODULE_PARM_DESC(frandom_bufsize,"Internal buffer size in bytes. Default is 256. Must be >= 256");
  +MODULE_PARM(frandom_chunklimit,"i");
  +MODULE_PARM_DESC(frandom_chunklimit,"Limit for read() blocks size. 0 (default) is unlimited, otherwise must be >= 256");
  +
  +struct frandom_state
  +{
  +	struct semaphore sem; /* Semaphore on the state structure */
  +
  +	u8 S[256]; /* The state array */
  +	u8 i;        
  +	u8 j;
  +
  +	char *buf;
  +};
  +
  +static struct frandom_state *erandom_state;
  +
  +static inline void swap_byte(u8 *a, u8 *b)
  +{
  +	u8 swapByte; 
  +  
  +	swapByte = *a; 
  +	*a = *b;      
  +	*b = swapByte;
  +}
  +
  +static void init_rand_state(struct frandom_state *state, int seedflag);
  +
  +void erandom_get_random_bytes(char *buf, size_t count)
  +{
  +	struct frandom_state *state = erandom_state;
  +	int k;
  +
  +	unsigned int i;
  +	unsigned int j;
  +	u8 *S;
  +  
  +	/* If we fail to get the semaphore, we revert to external random data.
  +	   Since semaphore blocking is expected to be very rare, and interrupts
  +	   during these rare and very short periods of time even less frequent,
  +	   we take the better-safe-than-sorry approach, and fill the buffer
  +	   some expensive random data, in case the caller wasn't aware of this
  +	   possibility, and expects random data anyhow.
  +	*/
  +
  +	if (down_interruptible(&state->sem)) {
  +		get_random_bytes(buf, count);
  +		return;
  +	}
  +
  +	/* We seed erandom as late as possible, hoping that the kernel's main
  +	   RNG is already restored in the boot sequence (not critical, but
  +	   better.
  +	*/
  +	
  +	if (!erandom_seeded) {
  +		erandom_seeded = 1;
  +		init_rand_state(state, EXTERNAL_SEED);
  +		printk(KERN_INFO "frandom: Seeded global generator now (used by erandom)\n");
  +	}
  +
  +	i = state->i;     
  +	j = state->j;
  +	S = state->S;  
  +
  +	for (k=0; k<count; k++) {
  +		i = (i + 1) & 0xff;
  +		j = (j + S[i]) & 0xff;
  +		swap_byte(&S[i], &S[j]);
  +		*buf++ = S[(S[i] + S[j]) & 0xff];
  +	}
  + 
  +	state->i = i;     
  +	state->j = j;
  +
  +	up(&state->sem);
  +}
  +
  +static void init_rand_state(struct frandom_state *state, int seedflag)
  +{
  +	unsigned int i, j, k;
  +	u8 *S;
  +	u8 *seed = state->buf;
  +
  +	if (seedflag == INTERNAL_SEED)
  +		erandom_get_random_bytes(seed, 256);
  +	else
  +		get_random_bytes(seed, 256);
  +
  +	S = state->S;
  +	for (i=0; i<256; i++)
  +		*S++=i;
  +
  +	j=0;
  +	S = state->S;
  +
  +	for (i=0; i<256; i++) {
  +		j = (j + S[i] + *seed++) & 0xff;
  +		swap_byte(&S[i], &S[j]);
  +	}
  +
  +	/* It's considered good practice to discard the first 256 bytes
  +	   generated. So we do it:
  +	*/
  +
  +	i=0; j=0;
  +	for (k=0; k<256; k++) {
  +		i = (i + 1) & 0xff;
  +		j = (j + S[i]) & 0xff;
  +		swap_byte(&S[i], &S[j]);
  +	}
  +
  +	state->i = i; /* Save state */
  +	state->j = j;
  +}
  +
  +static int frandom_open(struct inode *inode, struct file *filp)
  +{
  +  
  +	struct frandom_state *state;
  +
  +	int num =MINOR(inode->i_rdev);
  +	if ((num != frandom_minor) && (num != erandom_minor)) return -ENODEV;
  +  
  +	state = kmalloc(sizeof(struct frandom_state), GFP_KERNEL);
  +	if (!state)
  +		return -ENOMEM;
  +
  +	state->buf = kmalloc(frandom_bufsize, GFP_KERNEL);
  +	if (!state->buf) {
  +		kfree(state);
  +		return -ENOMEM;
  +	}
  +
  +	sema_init(&state->sem, 1); /* Init semaphore as a mutex */
  +
  +	if (num == frandom_minor)
  +		init_rand_state(state, EXTERNAL_SEED);
  +	else
  +		init_rand_state(state, INTERNAL_SEED);
  +
  +	filp->private_data = state;
  +
  +#if (LINUX_VERSION_CODE<KERNEL_VERSION(2,4,0))
  +	MOD_INC_USE_COUNT; 
  +#endif
  +  
  +	return 0; /* Success */
  +}
  +
  +static int frandom_release(struct inode *inode, struct file *filp)
  +{
  +
  +	struct frandom_state *state = filp->private_data;
  +
  +	kfree(state->buf);
  +	kfree(state);
  +  
  +#if (LINUX_VERSION_CODE<KERNEL_VERSION(2,4,0))
  +	MOD_DEC_USE_COUNT;
  +#endif
  +
  +	return 0;
  +}
  +
  +static ssize_t frandom_read(struct file *filp, char *buf, size_t count,
  +			    loff_t *f_pos)
  +{
  +	struct frandom_state *state = filp->private_data;
  +	ssize_t ret;
  +	int dobytes, k;
  +	char *localbuf;
  +
  +	unsigned int i;
  +	unsigned int j;
  +	u8 *S;
  +  
  +	if (down_interruptible(&state->sem))
  +		return -ERESTARTSYS;
  +  
  +	if ((frandom_chunklimit > 0) && (count > frandom_chunklimit))
  +		count = frandom_chunklimit;
  +
  +	ret = count; /* It's either everything or an error... */
  +  
  +	i = state->i;     
  +	j = state->j;
  +	S = state->S;  
  +
  +	while (count) {
  +		if (count > frandom_bufsize)
  +			dobytes = frandom_bufsize;
  +		else
  +			dobytes = count;
  +
  +		localbuf = state->buf;
  +
  +		for (k=0; k<dobytes; k++) {
  +			i = (i + 1) & 0xff;
  +			j = (j + S[i]) & 0xff;
  +			swap_byte(&S[i], &S[j]);
  +			*localbuf++ = S[(S[i] + S[j]) & 0xff];
  +		}
  + 
  +		if (copy_to_user(buf, state->buf, dobytes)) {
  +			ret = -EFAULT;
  +			goto out;
  +		}
  +
  +		buf += dobytes;
  +		count -= dobytes;
  +	}
  +
  + out:
  +	state->i = i;     
  +	state->j = j;
  +
  +	up(&state->sem);
  +	return ret;
  +}
  +
  +static struct file_operations frandom_fops = {
  +	read:       frandom_read,
  +	open:       frandom_open,
  +	release:    frandom_release,
  +};
  +
  +static void frandom_cleanup_module(void) {
  +	kfree(erandom_state->buf);
  +	kfree(erandom_state);
  + 
  +	unregister_chrdev(frandom_major, "frandom");
  +}
  +
  +
  +static int frandom_init_module(void)
  +{
  +	int result;
  +
  +	/* The buffer size MUST be at least 256 bytes, because we assume that
  +	   minimal length in init_rand_state().
  +	*/       
  +	if (frandom_bufsize < 256) {
  +		printk(KERN_ERR "frandom: Refused to load because frandom_bufsize=%d < 256\n",frandom_bufsize);
  +		return -EINVAL;
  +	}
  +	if ((frandom_chunklimit != 0) && (frandom_chunklimit < 256)) {
  +		printk(KERN_ERR "frandom: Refused to load because frandom_chunklimit=%d < 256 and != 0\n",frandom_chunklimit);
  +		return -EINVAL;
  +	}
  +
  +	erandom_state = kmalloc(sizeof(struct frandom_state), GFP_KERNEL);
  +	if (!erandom_state)
  +		return -ENOMEM;
  +
  +	/* This specific buffer is only used for seeding, so we need
  +	   256 bytes exactly */
  +	erandom_state->buf = kmalloc(256, GFP_KERNEL);
  +	if (!erandom_state->buf) {
  +		kfree(erandom_state);
  +		return -ENOMEM;
  +	}
  +
  +	sema_init(&erandom_state->sem, 1); /* Init semaphore as a mutex */
  +
  +	erandom_seeded = 0;
  +
  +#ifdef SET_MODULE_OWNER
  +	SET_MODULE_OWNER(&frandom_fops);
  +#endif
  +	/*
  +	 * Register your major, and accept a dynamic number. This is the
  +	 * first thing to do, in order to avoid releasing other module's
  +	 * fops in frandom_cleanup_module()
  +	 */
  +	result = register_chrdev(frandom_major, "frandom", &frandom_fops);
  +	if (result < 0) {
  +		printk(KERN_WARNING "frandom: can't get major %d\n",frandom_major);
  +
  +		kfree(erandom_state->buf);
  +		kfree(erandom_state);
  +	
  +		return result;
  +	}
  +	if (frandom_major == 0) frandom_major = result; /* dynamic */
  +    
  +	return 0; /* succeed */
  +}
  +
  +module_init(frandom_init_module);
  +module_exit(frandom_cleanup_module);
  +
  +EXPORT_SYMBOL(erandom_get_random_bytes);
  diff -Naur linux-2.4.26.orig/drivers/char/random.c linux-2.4.26.frandom/drivers/char/random.c
  --- linux-2.4.26.orig/drivers/char/random.c	2004-02-18 13:36:31.000000000 +0000
  +++ linux-2.4.26.frandom/drivers/char/random.c	2004-04-18 21:56:30.000000000 +0000
  @@ -1870,6 +1870,60 @@
   	return 1;
   }
   
  +#ifdef CONFIG_FRANDOM
  +/* We don't really want to create a header file for frandom
  +   at this stage, so here's the prototype: */
  +
  +void erandom_get_random_bytes(char *buf, size_t count);
  +
  +static int proc_do_erandom(ctl_table *table, int write, struct file *filp,
  +			void *buffer, size_t *lenp)
  +{
  +	ctl_table	fake_table;
  +	unsigned char	buf[64], random[16], *p;
  +	int i;
  +	
  +	erandom_get_random_bytes(random, 16);
  +	
  +	p=buf;
  +	
  +	for (i=0; i<16; i++) {
  +     		sprintf(p, "%02x", random[i]);
  +		p+=2;
  +	}
  +
  +	fake_table.data = buf;
  +	fake_table.maxlen = sizeof(buf);
  +
  +	return proc_dostring(&fake_table, write, filp, buffer, lenp);
  +}
  +
  +
  +static int erandom_strategy(ctl_table *table, int *name, int nlen,
  +			 void *oldval, size_t *oldlenp,
  +			 void *newval, size_t newlen, void **context)
  +{
  +	unsigned char	random[16];
  +	unsigned int	len;
  +
  +	if (!oldval || !oldlenp)
  +		return 1;
  +
  +	erandom_get_random_bytes(random, 16);
  +
  +	if (get_user(len, oldlenp))
  +		return -EFAULT;
  +	if (len) {
  +		if (len > 16)
  +			len = 16;
  +		if (copy_to_user(oldval, random, len) ||
  +		    put_user(len, oldlenp))
  +			return -EFAULT;
  +	}
  +	return 1;
  +}
  +#endif
  +
   ctl_table random_table[] = {
   	{RANDOM_POOLSIZE, "poolsize",
   	 &sysctl_poolsize, sizeof(int), 0644, NULL,
  @@ -1888,6 +1942,11 @@
   	{RANDOM_BOOT_ID, "boot_id",
   	 &sysctl_bootid, 16, 0444, NULL,
   	 &proc_do_uuid, &uuid_strategy},
  +#ifdef CONFIG_FRANDOM
  +	{RANDOM_ERANDOM, "erandom",
  +	 NULL, 16, 0444, NULL,
  +	 &proc_do_erandom, &erandom_strategy},
  +#endif
   	{RANDOM_UUID, "uuid",
   	 NULL, 16, 0444, NULL,
   	 &proc_do_uuid, &uuid_strategy},
  diff -Naur linux-2.4.26.orig/include/linux/sysctl.h linux-2.4.26.frandom/include/linux/sysctl.h
  --- linux-2.4.26.orig/include/linux/sysctl.h	2004-04-14 13:05:40.000000000 +0000
  +++ linux-2.4.26.frandom/include/linux/sysctl.h	2004-04-18 21:56:30.000000000 +0000
  @@ -190,7 +190,8 @@
   	RANDOM_READ_THRESH=3,
   	RANDOM_WRITE_THRESH=4,
   	RANDOM_BOOT_ID=5,
  -	RANDOM_UUID=6
  +	RANDOM_UUID=6,
  +	RANDOM_ERANDOM=7
   };
   
   /* /proc/sys/bus/isa */
  
  
  
  1.1                  patches/linux/linux-2.6.5-frandom-1.patch
  
  Index: linux-2.6.5-frandom-1.patch
  ===================================================================
  Submitted By: Robert Connolly <robert at linuxfromscratch dot org> (ashes)
  Date: 2004-05-07
  Initial Package Version: Linux 2.6.5
  Origin: http://frandom.sourceforge.net/ - frandom-0.8
  Description: This is usefull for smashing stack protector, wiping
  discs, mktemp, and more.
  
  Thanks to Eli Billauer
  http://www.billauer.co.il/
  http://frandom.sourceforge.net/
  
  Also see:
  http://www.linuxfromscratch.org/hlfs/
  http://www.linuxfromscratch.org/hints/downloads/files/entropy.txt
  http://www.linuxfromscratch.org/~robert/hlfs/hints/attachments/entropy/\
          frandom-0.8.tar.gz
  
  diff -Naur linux-2.6.5.orig/drivers/char/Kconfig linux-2.6.5.frandom/drivers/char/Kconfig
  --- linux-2.6.5.orig/drivers/char/Kconfig	2004-04-04 03:36:15.000000000 +0000
  +++ linux-2.6.5.frandom/drivers/char/Kconfig	2004-05-06 21:55:25.000000000 +0000
  @@ -57,6 +57,19 @@
   
   	  If unsure, say Y.
   
  +config FRANDOM
  +	tristate "Fast random data generator suite (/dev/frandom and /dev/erandom)"
  +	default y
  +	---help---
  +	Fast random data/number generator support in kernel. This random
  +	generator is 10-50 times faster than /dev/urandom, and saves kernel
  +	entropy.
  +
  +	If unsure, say Y unless you're tight on kernel size. This module is
  +	small and harmless otherwise.
  +
  +	If you choose M, the sysctl interface will be disabled.
  +
   config HW_CONSOLE
   	bool
   	depends on VT && !S390 && !UM
  diff -Naur linux-2.6.5.orig/drivers/char/Makefile linux-2.6.5.frandom/drivers/char/Makefile
  --- linux-2.6.5.orig/drivers/char/Makefile	2004-04-04 03:38:18.000000000 +0000
  +++ linux-2.6.5.frandom/drivers/char/Makefile	2004-05-06 21:55:42.000000000 +0000
  @@ -82,6 +82,8 @@
   obj-$(CONFIG_PCMCIA) += pcmcia/
   obj-$(CONFIG_IPMI_HANDLER) += ipmi/
   
  +obj-$(CONFIG_FRANDOM) += frandom.o
  +
   obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
   
   # Files generated that shall be removed upon make clean
  diff -Naur linux-2.6.5.orig/drivers/char/frandom.c linux-2.6.5.frandom/drivers/char/frandom.c
  --- linux-2.6.5.orig/drivers/char/frandom.c	1970-01-01 00:00:00.000000000 +0000
  +++ linux-2.6.5.frandom/drivers/char/frandom.c	2004-05-06 21:55:25.000000000 +0000
  @@ -0,0 +1,362 @@
  +/*
  +** frandom.c
  +**      Fast pseudo-random generator 
  +**
  +**      (c) Copyright 2003 Eli Billauer
  +**      http://www.billauer.co.il
  +**
  +** This program is free software; you can redistribute it and/or modify
  +** it under the terms of the GNU General Public License as published by
  +** the Free Software Foundation; either version 2 of the License, or
  +** (at your option) any later version.
  +**
  +** Usage: mknod /dev/frandom c 235 11
  +**        mknod /dev/erandom c 235 12
  +**        insmod frandom
  +**
  +** This code is highly based upon the examples given in the book "Linux
  +** Device Drivers" by Alessandro Rubini and Jonathan Corbet, published
  +** by O'Reilly & Associates.
  +** O'Reilly's release of this book on the web for free is highly
  +** appreciated.
  +**
  +*/
  +
  +#include <linux/version.h>
  +#include <linux/config.h>
  +#include <linux/module.h>
  +
  +#include <linux/kernel.h>
  +#include <linux/init.h>
  +#include <linux/slab.h> 
  +#include <linux/fs.h> 
  +#include <linux/errno.h>
  +#include <linux/types.h> 
  +#include <linux/random.h>
  +
  +#include <asm/uaccess.h>
  +
  +#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,0))
  +#include <linux/moduleparam.h>
  +#endif
  +
  +#define INTERNAL_SEED 0
  +#define EXTERNAL_SEED 1
  +
  +#define FRANDOM_MAJOR 235
  +#define FRANDOM_MINOR 11 
  +#define ERANDOM_MINOR 12 
  +
  +static struct file_operations frandom_fops; /* Values assigned below */
  +
  +static int erandom_seeded = 0; /* Internal flag */
  +
  +static int frandom_major = FRANDOM_MAJOR;
  +static int frandom_minor = FRANDOM_MINOR;
  +static int erandom_minor = ERANDOM_MINOR;
  +static int frandom_bufsize = 256;
  +static int frandom_chunklimit = 0; /* =0 means unlimited */
  +
  +MODULE_DESCRIPTION("Fast pseudo-random number generator");
  +MODULE_LICENSE("GPL");
  +MODULE_AUTHOR("Eli Billauer");
  +MODULE_PARM(frandom_major,"i");
  +MODULE_PARM_DESC(frandom_major,"Major number of /dev/frandom and /dev/erandom");
  +MODULE_PARM(frandom_minor,"i");
  +MODULE_PARM_DESC(frandom_minor,"Minor number of /dev/frandom");
  +MODULE_PARM(erandom_minor,"i");
  +MODULE_PARM_DESC(erandom_minor,"Minor number of /dev/erandom");
  +MODULE_PARM(frandom_bufsize,"i");
  +MODULE_PARM_DESC(frandom_bufsize,"Internal buffer size in bytes. Default is 256. Must be >= 256");
  +MODULE_PARM(frandom_chunklimit,"i");
  +MODULE_PARM_DESC(frandom_chunklimit,"Limit for read() blocks size. 0 (default) is unlimited, otherwise must be >= 256");
  +
  +struct frandom_state
  +{
  +	struct semaphore sem; /* Semaphore on the state structure */
  +
  +	u8 S[256]; /* The state array */
  +	u8 i;        
  +	u8 j;
  +
  +	char *buf;
  +};
  +
  +static struct frandom_state *erandom_state;
  +
  +static inline void swap_byte(u8 *a, u8 *b)
  +{
  +	u8 swapByte; 
  +  
  +	swapByte = *a; 
  +	*a = *b;      
  +	*b = swapByte;
  +}
  +
  +static void init_rand_state(struct frandom_state *state, int seedflag);
  +
  +void erandom_get_random_bytes(char *buf, size_t count)
  +{
  +	struct frandom_state *state = erandom_state;
  +	int k;
  +
  +	unsigned int i;
  +	unsigned int j;
  +	u8 *S;
  +  
  +	/* If we fail to get the semaphore, we revert to external random data.
  +	   Since semaphore blocking is expected to be very rare, and interrupts
  +	   during these rare and very short periods of time even less frequent,
  +	   we take the better-safe-than-sorry approach, and fill the buffer
  +	   some expensive random data, in case the caller wasn't aware of this
  +	   possibility, and expects random data anyhow.
  +	*/
  +
  +	if (down_interruptible(&state->sem)) {
  +		get_random_bytes(buf, count);
  +		return;
  +	}
  +
  +	/* We seed erandom as late as possible, hoping that the kernel's main
  +	   RNG is already restored in the boot sequence (not critical, but
  +	   better.
  +	*/
  +	
  +	if (!erandom_seeded) {
  +		erandom_seeded = 1;
  +		init_rand_state(state, EXTERNAL_SEED);
  +		printk(KERN_INFO "frandom: Seeded global generator now (used by erandom)\n");
  +	}
  +
  +	i = state->i;     
  +	j = state->j;
  +	S = state->S;  
  +
  +	for (k=0; k<count; k++) {
  +		i = (i + 1) & 0xff;
  +		j = (j + S[i]) & 0xff;
  +		swap_byte(&S[i], &S[j]);
  +		*buf++ = S[(S[i] + S[j]) & 0xff];
  +	}
  + 
  +	state->i = i;     
  +	state->j = j;
  +
  +	up(&state->sem);
  +}
  +
  +static void init_rand_state(struct frandom_state *state, int seedflag)
  +{
  +	unsigned int i, j, k;
  +	u8 *S;
  +	u8 *seed = state->buf;
  +
  +	if (seedflag == INTERNAL_SEED)
  +		erandom_get_random_bytes(seed, 256);
  +	else
  +		get_random_bytes(seed, 256);
  +
  +	S = state->S;
  +	for (i=0; i<256; i++)
  +		*S++=i;
  +
  +	j=0;
  +	S = state->S;
  +
  +	for (i=0; i<256; i++) {
  +		j = (j + S[i] + *seed++) & 0xff;
  +		swap_byte(&S[i], &S[j]);
  +	}
  +
  +	/* It's considered good practice to discard the first 256 bytes
  +	   generated. So we do it:
  +	*/
  +
  +	i=0; j=0;
  +	for (k=0; k<256; k++) {
  +		i = (i + 1) & 0xff;
  +		j = (j + S[i]) & 0xff;
  +		swap_byte(&S[i], &S[j]);
  +	}
  +
  +	state->i = i; /* Save state */
  +	state->j = j;
  +}
  +
  +static int frandom_open(struct inode *inode, struct file *filp)
  +{
  +  
  +	struct frandom_state *state;
  +
  +	int num =MINOR(inode->i_rdev);
  +	if ((num != frandom_minor) && (num != erandom_minor)) return -ENODEV;
  +  
  +	state = kmalloc(sizeof(struct frandom_state), GFP_KERNEL);
  +	if (!state)
  +		return -ENOMEM;
  +
  +	state->buf = kmalloc(frandom_bufsize, GFP_KERNEL);
  +	if (!state->buf) {
  +		kfree(state);
  +		return -ENOMEM;
  +	}
  +
  +	sema_init(&state->sem, 1); /* Init semaphore as a mutex */
  +
  +	if (num == frandom_minor)
  +		init_rand_state(state, EXTERNAL_SEED);
  +	else
  +		init_rand_state(state, INTERNAL_SEED);
  +
  +	filp->private_data = state;
  +
  +#if (LINUX_VERSION_CODE<KERNEL_VERSION(2,4,0))
  +	MOD_INC_USE_COUNT; 
  +#endif
  +  
  +	return 0; /* Success */
  +}
  +
  +static int frandom_release(struct inode *inode, struct file *filp)
  +{
  +
  +	struct frandom_state *state = filp->private_data;
  +
  +	kfree(state->buf);
  +	kfree(state);
  +  
  +#if (LINUX_VERSION_CODE<KERNEL_VERSION(2,4,0))
  +	MOD_DEC_USE_COUNT;
  +#endif
  +
  +	return 0;
  +}
  +
  +static ssize_t frandom_read(struct file *filp, char *buf, size_t count,
  +			    loff_t *f_pos)
  +{
  +	struct frandom_state *state = filp->private_data;
  +	ssize_t ret;
  +	int dobytes, k;
  +	char *localbuf;
  +
  +	unsigned int i;
  +	unsigned int j;
  +	u8 *S;
  +  
  +	if (down_interruptible(&state->sem))
  +		return -ERESTARTSYS;
  +  
  +	if ((frandom_chunklimit > 0) && (count > frandom_chunklimit))
  +		count = frandom_chunklimit;
  +
  +	ret = count; /* It's either everything or an error... */
  +  
  +	i = state->i;     
  +	j = state->j;
  +	S = state->S;  
  +
  +	while (count) {
  +		if (count > frandom_bufsize)
  +			dobytes = frandom_bufsize;
  +		else
  +			dobytes = count;
  +
  +		localbuf = state->buf;
  +
  +		for (k=0; k<dobytes; k++) {
  +			i = (i + 1) & 0xff;
  +			j = (j + S[i]) & 0xff;
  +			swap_byte(&S[i], &S[j]);
  +			*localbuf++ = S[(S[i] + S[j]) & 0xff];
  +		}
  + 
  +		if (copy_to_user(buf, state->buf, dobytes)) {
  +			ret = -EFAULT;
  +			goto out;
  +		}
  +
  +		buf += dobytes;
  +		count -= dobytes;
  +	}
  +
  + out:
  +	state->i = i;     
  +	state->j = j;
  +
  +	up(&state->sem);
  +	return ret;
  +}
  +
  +static struct file_operations frandom_fops = {
  +	read:       frandom_read,
  +	open:       frandom_open,
  +	release:    frandom_release,
  +};
  +
  +static void frandom_cleanup_module(void) {
  +	kfree(erandom_state->buf);
  +	kfree(erandom_state);
  + 
  +	unregister_chrdev(frandom_major, "frandom");
  +}
  +
  +
  +static int frandom_init_module(void)
  +{
  +	int result;
  +
  +	/* The buffer size MUST be at least 256 bytes, because we assume that
  +	   minimal length in init_rand_state().
  +	*/       
  +	if (frandom_bufsize < 256) {
  +		printk(KERN_ERR "frandom: Refused to load because frandom_bufsize=%d < 256\n",frandom_bufsize);
  +		return -EINVAL;
  +	}
  +	if ((frandom_chunklimit != 0) && (frandom_chunklimit < 256)) {
  +		printk(KERN_ERR "frandom: Refused to load because frandom_chunklimit=%d < 256 and != 0\n",frandom_chunklimit);
  +		return -EINVAL;
  +	}
  +
  +	erandom_state = kmalloc(sizeof(struct frandom_state), GFP_KERNEL);
  +	if (!erandom_state)
  +		return -ENOMEM;
  +
  +	/* This specific buffer is only used for seeding, so we need
  +	   256 bytes exactly */
  +	erandom_state->buf = kmalloc(256, GFP_KERNEL);
  +	if (!erandom_state->buf) {
  +		kfree(erandom_state);
  +		return -ENOMEM;
  +	}
  +
  +	sema_init(&erandom_state->sem, 1); /* Init semaphore as a mutex */
  +
  +	erandom_seeded = 0;
  +
  +#ifdef SET_MODULE_OWNER
  +	SET_MODULE_OWNER(&frandom_fops);
  +#endif
  +	/*
  +	 * Register your major, and accept a dynamic number. This is the
  +	 * first thing to do, in order to avoid releasing other module's
  +	 * fops in frandom_cleanup_module()
  +	 */
  +	result = register_chrdev(frandom_major, "frandom", &frandom_fops);
  +	if (result < 0) {
  +		printk(KERN_WARNING "frandom: can't get major %d\n",frandom_major);
  +
  +		kfree(erandom_state->buf);
  +		kfree(erandom_state);
  +	
  +		return result;
  +	}
  +	if (frandom_major == 0) frandom_major = result; /* dynamic */
  +    
  +	return 0; /* succeed */
  +}
  +
  +module_init(frandom_init_module);
  +module_exit(frandom_cleanup_module);
  +
  +EXPORT_SYMBOL(erandom_get_random_bytes);
  diff -Naur linux-2.6.5.orig/drivers/char/random.c linux-2.6.5.frandom/drivers/char/random.c
  --- linux-2.6.5.orig/drivers/char/random.c	2004-04-04 03:36:17.000000000 +0000
  +++ linux-2.6.5.frandom/drivers/char/random.c	2004-05-06 21:55:25.000000000 +0000
  @@ -1982,6 +1982,59 @@
   	return 1;
   }
   
  +#ifdef CONFIG_FRANDOM
  +/* We don't really want to create a header file for frandom
  +   at this stage, so here's the prototype: */
  +
  +void erandom_get_random_bytes(char *buf, size_t count);
  +
  +static int proc_do_erandom(ctl_table *table, int write, struct file *filp,
  +                       void *buffer, size_t *lenp)
  +{
  +       ctl_table       fake_table;
  +       unsigned char   buf[64], random[16], *p;
  +       int i;
  +
  +       erandom_get_random_bytes(random, 16);
  +
  +       p=buf;
  +
  +       for (i=0; i<16; i++) {
  +               sprintf(p, "%02x", random[i]);
  +               p+=2;
  +       }
  +
  +       fake_table.data = buf;
  +       fake_table.maxlen = sizeof(buf);
  +
  +       return proc_dostring(&fake_table, write, filp, buffer, lenp);
  +}
  +
  +static int erandom_strategy(ctl_table *table, int *name, int nlen,
  +                        void *oldval, size_t *oldlenp,
  +                        void *newval, size_t newlen, void **context)
  +{
  +       unsigned char   random[16];
  +       unsigned int    len;
  +
  +       if (!oldval || !oldlenp)
  +               return 1;
  +
  +       erandom_get_random_bytes(random, 16);
  +
  +       if (get_user(len, oldlenp))
  +               return -EFAULT;
  +       if (len) {
  +               if (len > 16)
  +                       len = 16;
  +               if (copy_to_user(oldval, random, len) ||
  +                   put_user(len, oldlenp))
  +                       return -EFAULT;
  +       }
  +       return 1;
  +}
  +#endif
  +
   ctl_table random_table[] = {
   	{
   		.ctl_name	= RANDOM_POOLSIZE,
  @@ -2038,6 +2091,16 @@
   		.proc_handler	= &proc_do_uuid,
   		.strategy	= &uuid_strategy,
   	},
  +#ifdef CONFIG_FRANDOM
  +	{
  +		.ctl_name	= RANDOM_ERANDOM,
  +		.procname	= "erandom",
  +		.maxlen		= 16,
  +		.mode		= 0444,
  +		.proc_handler	= &proc_do_erandom,
  +		.strategy	= &erandom_strategy,
  +	},
  +#endif
   	{ .ctl_name = 0 }
   };
   
  diff -Naur linux-2.6.5.orig/include/linux/sysctl.h linux-2.6.5.frandom/include/linux/sysctl.h
  --- linux-2.6.5.orig/include/linux/sysctl.h	2004-04-04 03:37:23.000000000 +0000
  +++ linux-2.6.5.frandom/include/linux/sysctl.h	2004-05-06 21:55:25.000000000 +0000
  @@ -192,7 +192,8 @@
   	RANDOM_READ_THRESH=3,
   	RANDOM_WRITE_THRESH=4,
   	RANDOM_BOOT_ID=5,
  -	RANDOM_UUID=6
  +	RANDOM_UUID=6,
  +	RANDOM_ERANDOM=7
   };
   
   /* /proc/sys/kernel/pty */
  
  
  



More information about the patches mailing list