diff -Naur linux-2.6.16.19.orig/arch/um/Kconfig.char linux-2.6.16.19/arch/um/Kconfig.char
--- linux-2.6.16.19.orig/arch/um/Kconfig.char 2006-05-31 00:31:44.000000000 +0000
+++ linux-2.6.16.19/arch/um/Kconfig.char 2006-06-01 01:21:06.000000000 +0000
@@ -204,6 +204,24 @@
http://sourceforge.net/projects/gkernel/). rngd periodically reads
/dev/hwrng and injects the entropy into /dev/random.
+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. Erandom is available via sysctl(2) if SYSCTL and FRANDOM
+ are compiled into the kernel (not as a module). Frandom uses kernel
+ entropy for its initial seed. Erandom uses Frandom's pool for a seed
+ and does not deplete kernel entropy.
+
+ If unsure, say Y unless you're tight on kernel size. This module is
+ small and harmless otherwise.
+
+ See:
+
+ If you choose M, the sysctl interface will be disabled.
+
config MMAPPER
tristate "iomem emulation driver"
help
diff -Naur linux-2.6.16.19.orig/drivers/char/Kconfig linux-2.6.16.19/drivers/char/Kconfig
--- linux-2.6.16.19.orig/drivers/char/Kconfig 2006-05-31 00:31:44.000000000 +0000
+++ linux-2.6.16.19/drivers/char/Kconfig 2006-06-01 01:16:51.000000000 +0000
@@ -57,6 +57,48 @@
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. Erandom is available via sysctl(2) if SYSCTL and FRANDOM
+ are compiled into the kernel (not as a module). Frandom uses kernel
+ entropy for its initial seed. Erandom uses Frandom's pool for a seed
+ and does not deplete kernel entropy.
+
+ If unsure, say Y unless you're tight on kernel size. This module is
+ small and harmless otherwise.
+
+ See:
+
+ If you choose M, the sysctl interface will be disabled.
+
+config SYSCTL_ERANDOM
+ bool "Sysctl erandom interface"
+ depends on SYSCTL && FRANDOM=y
+ default y
+ ---help---
+ If you say Y here Economical Random will be available from sysctl
+ kernel.random.erandom. The advantage of this is that Erandom is
+ accessible from inside a chroot. Erandom is a non-blocking interface.
+
+ See:
+
+ If unsure, say Y unless you're tight on kernel size.
+
+config SYSCTL_URANDOM
+ bool "Sysctl urandom interface"
+ depends on SYSCTL
+ default y
+ ---help---
+ If you say Y here get_random_bytes() will be available from sysctl
+ kernel.random.urandom. The main advantage to this is to be able to
+ access urandom through a chroot.
+
+ If unsure, say Y unless you're tight on kernel size.
+
config HW_CONSOLE
bool
depends on VT && !S390 && !UML
diff -Naur linux-2.6.16.19.orig/drivers/char/Makefile linux-2.6.16.19/drivers/char/Makefile
--- linux-2.6.16.19.orig/drivers/char/Makefile 2006-05-31 00:31:44.000000000 +0000
+++ linux-2.6.16.19/drivers/char/Makefile 2006-06-01 00:14:51.000000000 +0000
@@ -9,6 +9,8 @@
obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o
+obj-$(CONFIG_FRANDOM) += frandom.o
+
obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o
obj-y += misc.o
diff -Naur linux-2.6.16.19.orig/drivers/char/frandom.c linux-2.6.16.19/drivers/char/frandom.c
--- linux-2.6.16.19.orig/drivers/char/frandom.c 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16.19/drivers/char/frandom.c 2006-06-01 01:57:56.000000000 +0000
@@ -0,0 +1,379 @@
+/*
+** 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
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,0))
+#include
+#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; ki = 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;
+
+ 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);
+
+ 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; kbuf, 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 const struct {
+ unsigned int minor;
+ char *name;
+ umode_t mode;
+ struct file_operations *fops;
+} devlist[] = {
+ {11, "frandom", S_IRUGO | S_IWUSR, &frandom_fops},
+ /* Erandom doesn't have its own fop, it shares one with frandom. */
+ {12, "erandom", S_IRUGO | S_IWUSR, &frandom_fops},
+};
+
+static struct class *frandom_class;
+
+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, i=0;
+
+ /* 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 */
+
+ frandom_class = class_create(THIS_MODULE, "frandom");
+ for (i = 0; i < ARRAY_SIZE(devlist); i++) {
+ class_device_create(frandom_class, NULL,
+ MKDEV(FRANDOM_MAJOR, devlist[i].minor),
+ NULL, devlist[i].name);
+ devfs_mk_cdev(MKDEV(FRANDOM_MAJOR, devlist[i].minor),
+ S_IFCHR | devlist[i].mode, devlist[i].name);
+ }
+
+ return 0; /* succeed */
+}
+
+module_init(frandom_init_module);
+module_exit(frandom_cleanup_module);
+
+EXPORT_SYMBOL(erandom_get_random_bytes);
diff -Naur linux-2.6.16.19.orig/drivers/char/random.c linux-2.6.16.19/drivers/char/random.c
--- linux-2.6.16.19.orig/drivers/char/random.c 2006-05-31 00:31:44.000000000 +0000
+++ linux-2.6.16.19/drivers/char/random.c 2006-06-03 02:46:57.000000000 +0000
@@ -1227,6 +1227,106 @@
return 1;
}
+#ifdef CONFIG_SYSCTL_URANDOM
+static int proc_do_urandom(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp, loff_t *ppos)
+{
+ ctl_table fake_table;
+ unsigned char buf[1024], random[256], *p;
+ int i;
+
+ get_random_bytes(random, 256);
+
+ p=buf;
+
+ for (i=0; i<256; 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, ppos);
+}
+
+static int urandom_strategy(ctl_table *table, int *name, int nlen,
+ void *oldval, size_t *oldlenp,
+ void *newval, size_t newlen, void **context)
+{
+ unsigned char random[256];
+ unsigned int len;
+
+ if (!oldval || !oldlenp)
+ return 1;
+
+ get_random_bytes(random, 256);
+
+ if (get_user(len, oldlenp))
+ return -EFAULT;
+ if (len) {
+ if (len > 256)
+ len = 256;
+ if (copy_to_user(oldval, random, len) ||
+ put_user(len, oldlenp))
+ return -EFAULT;
+ }
+ return 1;
+}
+#endif
+
+#ifdef CONFIG_FRANDOM
+void erandom_get_random_bytes(char *buf, size_t count);
+
+#ifdef CONFIG_SYSCTL_ERANDOM
+static int proc_do_erandom(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp, loff_t *ppos)
+{
+ ctl_table fake_table;
+ unsigned char buf[1024], random[256], *p;
+ int i;
+
+ erandom_get_random_bytes(random, 256);
+
+ p=buf;
+
+ for (i=0; i<256; 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, ppos);
+}
+
+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[256];
+ unsigned int len;
+
+ if (!oldval || !oldlenp)
+ return 1;
+
+ erandom_get_random_bytes(random, 256);
+
+ if (get_user(len, oldlenp))
+ return -EFAULT;
+ if (len) {
+ if (len > 256)
+ len = 256;
+ if (copy_to_user(oldval, random, len) ||
+ put_user(len, oldlenp))
+ return -EFAULT;
+ }
+ return 1;
+}
+#endif /* CONFIG_FRANDOM */
+#endif /* CONFIG_SYSCTL_ERANDOM */
+
static int sysctl_poolsize = INPUT_POOL_WORDS * 32;
ctl_table random_table[] = {
{
@@ -1284,6 +1384,26 @@
.proc_handler = &proc_do_uuid,
.strategy = &uuid_strategy,
},
+#ifdef CONFIG_SYSCTL_URANDOM
+ {
+ .ctl_name = RANDOM_URANDOM,
+ .procname = "urandom",
+ .maxlen = 256,
+ .mode = 0444,
+ .proc_handler = &proc_do_urandom,
+ .strategy = &urandom_strategy,
+ },
+#endif /* CONFIG_SYSCTL_URANDOM */
+#ifdef CONFIG_SYSCTL_ERANDOM
+ {
+ .ctl_name = RANDOM_ERANDOM,
+ .procname = "erandom",
+ .maxlen = 256,
+ .mode = 0444,
+ .proc_handler = &proc_do_erandom,
+ .strategy = &erandom_strategy,
+ },
+#endif /* CONFIG_SYSCTL_ERANDOM */
{ .ctl_name = 0 }
};
#endif /* CONFIG_SYSCTL */
diff -Naur linux-2.6.16.19.orig/include/linux/sysctl.h linux-2.6.16.19/include/linux/sysctl.h
--- linux-2.6.16.19.orig/include/linux/sysctl.h 2006-05-31 00:31:44.000000000 +0000
+++ linux-2.6.16.19/include/linux/sysctl.h 2006-06-01 00:14:51.000000000 +0000
@@ -214,6 +214,8 @@
};
/* /proc/sys/kernel/random */
+#define SYSCTL_URANDOM
+#define SYSCTL_ERANDOM
enum
{
RANDOM_POOLSIZE=1,
@@ -221,7 +223,9 @@
RANDOM_READ_THRESH=3,
RANDOM_WRITE_THRESH=4,
RANDOM_BOOT_ID=5,
- RANDOM_UUID=6
+ RANDOM_UUID=6,
+ RANDOM_URANDOM=7,
+ RANDOM_ERANDOM=8
};
/* /proc/sys/kernel/pty */