Hi. Some things have changed in linux-2.6.12, this patch is for early testing. 
Please add it to the linux/ directory.

robert
Submitted By: Robert Connolly <robert at linuxfromscratch dot org> (ashes)
Date: 2005-06-19
Initial Package Version: 2.6.12
Upstream Status: Not submitted
Origin: http://frandom.sourceforge.net/
Description: This patch adds the he frandom, and erandom devices, and a
sysctl interface for urandom. Udev's permissions need modifications to add
/dev/frandom and /dev/erandom.

Also see:
http://www.linuxfromscratch.org/hlfs/
http://www.linuxfromscratch.org/hints/downloads/files/entropy.txt

diff -Naur linux-2.6.12-rc6-mm1.orig/drivers/char/Kconfig 
linux-2.6.12-rc6-mm1/drivers/char/Kconfig
--- linux-2.6.12-rc6-mm1.orig/drivers/char/Kconfig      2005-03-02 
07:37:45.000000000 +0000
+++ linux-2.6.12-rc6-mm1/drivers/char/Kconfig   2005-06-19 22:19:33.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 && !USERMODE
diff -Naur linux-2.6.12-rc6-mm1.orig/drivers/char/Makefile 
linux-2.6.12-rc6-mm1/drivers/char/Makefile
--- linux-2.6.12-rc6-mm1.orig/drivers/char/Makefile     2005-03-02 
07:38:26.000000000 +0000
+++ linux-2.6.12-rc6-mm1/drivers/char/Makefile  2005-06-19 22:19:33.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.12-rc6-mm1.orig/drivers/char/frandom.c 
linux-2.6.12-rc6-mm1/drivers/char/frandom.c
--- linux-2.6.12-rc6-mm1.orig/drivers/char/frandom.c    1970-01-01 
00:00:00.000000000 +0000
+++ linux-2.6.12-rc6-mm1/drivers/char/frandom.c 2005-06-19 22:22:24.000000000 
+0000
@@ -0,0 +1,387 @@
+/*
+** 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 <linux/devfs_fs_kernel.h>
+#include <linux/device.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 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,
+                                       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.12-rc6-mm1.orig/drivers/char/random.c 
linux-2.6.12-rc6-mm1/drivers/char/random.c
--- linux-2.6.12-rc6-mm1.orig/drivers/char/random.c     2005-03-02 
07:37:48.000000000 +0000
+++ linux-2.6.12-rc6-mm1/drivers/char/random.c  2005-06-19 22:19:33.000000000 
+0000
@@ -1891,6 +1891,104 @@
        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[64], random[16], *p;
+       int i;
+
+       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, 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[16];
+       unsigned int    len;
+
+       if (!oldval || !oldlenp)
+               return 1;
+
+       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
+
+#ifdef CONFIG_FRANDOM
+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, loff_t *ppos)
+{
+       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, 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[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
+
 static int sysctl_poolsize = DEFAULT_POOL_SIZE;
 ctl_table random_table[] = {
        {
@@ -1947,6 +2045,26 @@
                .proc_handler   = &proc_do_uuid,
                .strategy       = &uuid_strategy,
        },
+#ifdef CONFIG_SYSCTL_URANDOM
+       {
+               .ctl_name       = RANDOM_URANDOM,
+               .procname       = "urandom",
+               .maxlen         = 16,
+               .mode           = 0444,
+               .proc_handler   = &proc_do_urandom,
+               .strategy       = &urandom_strategy,
+       },
+#endif
+#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.12-rc6-mm1.orig/include/linux/sysctl.h 
linux-2.6.12-rc6-mm1/include/linux/sysctl.h
--- linux-2.6.12-rc6-mm1.orig/include/linux/sysctl.h    2005-03-02 
07:38:10.000000000 +0000
+++ linux-2.6.12-rc6-mm1/include/linux/sysctl.h 2005-06-19 22:19:33.000000000 
+0000
@@ -195,6 +195,8 @@
 };
 
 /* /proc/sys/kernel/random */
+#define SYSCTL_URANDOM
+#define SYSCTL_ERANDOM
 enum
 {
        RANDOM_POOLSIZE=1,
@@ -202,7 +204,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 */
diff -Naur linux-2.6.12-rc6-mm1.orig/init/Kconfig 
linux-2.6.12-rc6-mm1/init/Kconfig
--- linux-2.6.12-rc6-mm1.orig/init/Kconfig      2005-03-02 07:38:19.000000000 
+0000
+++ linux-2.6.12-rc6-mm1/init/Kconfig   2005-06-19 22:19:33.000000000 +0000
@@ -154,6 +154,16 @@
          building a kernel for install/rescue disks or your system is very
          limited in memory.
 
+config SYSCTL_URANDOM
+       bool "Sysctl urandom support"
+       depends on SYSCTL
+       default y
+       ---help---
+         If you say Y here, hooks will be enabled to access get_random_bytes()
+         from sysctl kernel.random.urandom. This is a non-blocking interface.
+         The main advantage to this is to be able to access urandom through
+         a chroot.
+
 config AUDIT
        bool "Auditing support"
        default y if SECURITY_SELINUX
-- 
http://linuxfromscratch.org/mailman/listinfo/patches
FAQ: http://www.linuxfromscratch.org/faq/
Unsubscribe: See the above information page

Reply via email to