aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/random
diff options
context:
space:
mode:
authorMark Murray <markm@FreeBSD.org>2000-10-14 10:59:56 +0000
committerMark Murray <markm@FreeBSD.org>2000-10-14 10:59:56 +0000
commita6278a2a42fc77094f356a290336a0fc395feb05 (patch)
tree1491a3f50ee42850d5f352e03d37c45d7a154565 /sys/dev/random
parent1b3c07c8934c7ed6f1bb68816c9d2a0a66fef3ff (diff)
downloadsrc-a6278a2a42fc77094f356a290336a0fc395feb05.tar.gz
src-a6278a2a42fc77094f356a290336a0fc395feb05.zip
After some complaints about the dir names, the random device is
now in dirs called sys/*/random/ instead of sys/*/randomdev/*. Introduce blocking, but only at startup; the random device will block until the first reseed happens to prevent clients from using untrustworthy output. Provide a read_random() call for the rest of the kernel so that the entropy device does not need to be present. This means that things like IPX no longer need to have "device random" hardcoded into thir kernel config. The downside is that read_random() will provide very poor output until the entropy device is loaded and reseeded. It is recommended that developers do NOT use the read_random() call; instead, they should use arc4random() which internally uses read_random(). Clean up the mutex and locking code a bit; this makes it possible to unload the module again.
Notes
Notes: svn path=/head/; revision=67112
Diffstat (limited to 'sys/dev/random')
-rw-r--r--sys/dev/random/harvest.c77
-rw-r--r--sys/dev/random/hash.c2
-rw-r--r--sys/dev/random/randomdev.c46
-rw-r--r--sys/dev/random/yarrow.c65
-rw-r--r--sys/dev/random/yarrow.h10
5 files changed, 139 insertions, 61 deletions
diff --git a/sys/dev/random/harvest.c b/sys/dev/random/harvest.c
index 4bfac55f5e7d..2f9ac2baa0c7 100644
--- a/sys/dev/random/harvest.c
+++ b/sys/dev/random/harvest.c
@@ -31,30 +31,38 @@
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/kthread.h>
+#include <sys/poll.h>
+#include <sys/select.h>
#include <sys/random.h>
#include <sys/time.h>
+#include <machine/mutex.h>
#include <crypto/blowfish/blowfish.h>
-#include <dev/randomdev/hash.h>
-#include <dev/randomdev/yarrow.h>
+#include <dev/random/hash.h>
+#include <dev/random/yarrow.h>
+
+static u_int read_random_phony(void *, u_int);
/* hold the address of the routine which is actually called if
* the ramdomdev is loaded
*/
-static void (*reap)(struct timespec *, void *, u_int, u_int, u_int, u_int) = NULL;
+static void (*reap_func)(struct timespec *, void *, u_int, u_int, u_int, u_int) = NULL;
+static u_int (*read_func)(void *, u_int) = read_random_phony;
/* Initialise the harvester at load time */
void
-random_init_harvester(void (*reaper)(struct timespec *, void *, u_int, u_int, u_int, u_int))
+random_init_harvester(void (*reaper)(struct timespec *, void *, u_int, u_int, u_int, u_int), u_int (*reader)(void *, u_int))
{
- reap = reaper;
+ reap_func = reaper;
+ read_func = reader;
}
/* Deinitialise the harvester at unload time */
void
random_deinit_harvester(void)
{
- reap = NULL;
+ reap_func = NULL;
+ read_func = read_random_phony;
}
/* Entropy harvesting routine. This is supposed to be fast; do
@@ -67,25 +75,60 @@ random_harvest(void *entropy, u_int count, u_int bits, u_int frac, u_int origin)
{
struct timespec timebuf;
- if (reap) {
+ if (reap_func) {
nanotime(&timebuf);
- (*reap)(&timebuf, entropy, count, bits, frac, origin);
+ (*reap_func)(&timebuf, entropy, count, bits, frac, origin);
}
}
-/* Helper routines to enable kthread_exit() to work while the module is
- * being (or has been) unloaded.
+/* Userland-visible version of read_random */
+u_int
+read_random(void *buf, u_int count)
+{
+ return (*read_func)(buf, count);
+}
+
+/* If the entropy device is not loaded, make a token effort to
+ * provide _some_ kind of randomness. This should only be used
+ * inside other RNG's, like arc4random(9).
*/
-void
-random_set_wakeup(int *var, int value)
+static u_int
+read_random_phony(void *buf, u_int count)
{
- *var = value;
- wakeup(var);
+ struct timespec timebuf;
+ u_long randval;
+ int size, i;
+ static int initialised = 0;
+
+ /* Try to give random(9) a half decent initialisation
+ * DO not make the mistake of thinking this is secure!!
+ */
+ if (!initialised) {
+ nanotime(&timebuf);
+ srandom((u_long)(timebuf.tv_sec ^ timebuf.tv_nsec));
+ }
+
+ /* Fill buf[] with random(9) output */
+ for (i = 0; i < count; i+= sizeof(u_long)) {
+ randval = random();
+ size = (count - i) < sizeof(u_long) ? (count - i) : sizeof(u_long);
+ memcpy(&((char *)buf)[i], &randval, size);
+ }
+
+ return count;
}
+/* Helper routine to enable kthread_exit() to work while the module is
+ * being (or has been) unloaded.
+ * This routine is in this file because it is always linked into the kernel,
+ * and will thus never be unloaded. This is critical for unloadable modules
+ * that have threads.
+ */
void
-random_set_wakeup_exit(int *var, int value, int exitval)
+random_set_wakeup_exit(void *control)
{
- random_set_wakeup(var, value);
- kthread_exit(exitval);
+ wakeup(control);
+ mtx_enter(&Giant, MTX_DEF);
+ kthread_exit(0);
+ /* NOTREACHED */
}
diff --git a/sys/dev/random/hash.c b/sys/dev/random/hash.c
index 432a54bc7c00..47bf7c2e1660 100644
--- a/sys/dev/random/hash.c
+++ b/sys/dev/random/hash.c
@@ -35,7 +35,7 @@
#include <sys/types.h>
#include <crypto/blowfish/blowfish.h>
-#include <dev/randomdev/hash.h>
+#include <dev/random/hash.h>
/* initialise the hash by copying in some supplied data */
void
diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c
index d6796ef5b187..eaa47b9ed5f7 100644
--- a/sys/dev/random/randomdev.c
+++ b/sys/dev/random/randomdev.c
@@ -36,20 +36,24 @@
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/bus.h>
+#include <sys/poll.h>
#include <sys/proc.h>
+#include <sys/select.h>
#include <sys/random.h>
+#include <sys/vnode.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/sysctl.h>
#include <crypto/blowfish/blowfish.h>
-#include <dev/randomdev/hash.h>
-#include <dev/randomdev/yarrow.h>
+#include <dev/random/hash.h>
+#include <dev/random/yarrow.h>
static d_open_t random_open;
static d_read_t random_read;
static d_write_t random_write;
static d_ioctl_t random_ioctl;
+static d_poll_t random_poll;
#define CDEV_MAJOR 2
#define RANDOM_MINOR 3
@@ -61,7 +65,7 @@ static struct cdevsw random_cdevsw = {
/* read */ random_read,
/* write */ random_write,
/* ioctl */ random_ioctl,
- /* poll */ nopoll,
+ /* poll */ random_poll,
/* mmap */ nommap,
/* strategy */ nostrategy,
/* name */ "random",
@@ -105,13 +109,22 @@ random_read(dev_t dev, struct uio *uio, int flag)
int error = 0;
void *random_buf;
- c = min(uio->uio_resid, PAGE_SIZE);
- random_buf = (void *)malloc(c, M_TEMP, M_WAITOK);
- while (uio->uio_resid > 0 && error == 0) {
- ret = read_random(random_buf, c);
- error = uiomove(random_buf, ret, uio);
+ if (flag & IO_NDELAY && !random_state.seeded) {
+ error = EWOULDBLOCK;
+ }
+ else {
+ if (random_state.seeded) {
+ c = min(uio->uio_resid, PAGE_SIZE);
+ random_buf = (void *)malloc(c, M_TEMP, M_WAITOK);
+ while (uio->uio_resid > 0 && error == 0) {
+ ret = read_random_real(random_buf, c);
+ error = uiomove(random_buf, ret, uio);
+ }
+ free(random_buf, M_TEMP);
+ }
+ else
+ error = tsleep(&random_state, 0, "rndblk", 0);
}
- free(random_buf, M_TEMP);
return error;
}
@@ -141,6 +154,21 @@ random_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
static int
+random_poll(dev_t dev, int events, struct proc *p)
+{
+ int revents;
+
+ revents = 0;
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (random_state.seeded)
+ revents = events & (POLLIN | POLLRDNORM);
+ else
+ selrecord(p, &random_state.rsel);
+ }
+ return revents;
+}
+
+static int
random_modevent(module_t mod, int type, void *data)
{
int error;
diff --git a/sys/dev/random/yarrow.c b/sys/dev/random/yarrow.c
index 1360d8e8dae0..fe4d160f7e92 100644
--- a/sys/dev/random/yarrow.c
+++ b/sys/dev/random/yarrow.c
@@ -38,6 +38,7 @@
#include <sys/libkern.h>
#include <sys/malloc.h>
#include <sys/proc.h>
+#include <sys/select.h>
#include <sys/random.h>
#include <sys/time.h>
#include <sys/types.h>
@@ -45,8 +46,8 @@
#include <machine/mutex.h>
#include <crypto/blowfish/blowfish.h>
-#include <dev/randomdev/hash.h>
-#include <dev/randomdev/yarrow.h>
+#include <dev/random/hash.h>
+#include <dev/random/yarrow.h>
/* #define DEBUG */
/* #define DEBUG1 */ /* Very noisy - prints plenty harvesting stats */
@@ -65,11 +66,11 @@ TAILQ_HEAD(harvestqueue, harvest) harvestqueue,
initqueue = TAILQ_HEAD_INITIALIZER(harvestqueue);
/* These are used to queue harvested packets of entropy. The entropy
- * buffer size of 16 is pretty arbitrary.
+ * buffer size is pretty arbitrary.
*/
struct harvest {
struct timespec time; /* nanotime for clock jitter */
- u_char entropy[16]; /* the harvested entropy */
+ u_char entropy[HARVESTSIZE]; /* the harvested entropy */
u_int size, bits, frac; /* stats about the entropy */
enum esource source; /* stats about the entropy */
u_int pool; /* which pool this goes into */
@@ -79,19 +80,18 @@ struct harvest {
/* The reseed thread mutex */
static struct mtx random_reseed_mtx;
-/* The entropy harvest mutex */
+/* The entropy harvest mutex, as well as the mutex associated
+ * with the msleep() call during deinit
+ */
static struct mtx random_harvest_mtx;
-/* <0 until the kthread starts, 0 for running */
-static int random_kthread_status = -1;
-
/* <0 to end the kthread, 0 to let it run */
static int random_kthread_control = 0;
static struct proc *random_kthread_proc;
static void
-random_kthread(void *status)
+random_kthread(void *arg /* NOTUSED */)
{
int pl, src, overthreshhold[2];
struct harvest *event;
@@ -101,10 +101,8 @@ random_kthread(void *status)
#endif
#ifdef DEBUG
- printf("At %s, line %d: mtx_owned(&Giant) == %d\n", __FILE__, __LINE__, mtx_owned(&Giant));
- printf("At %s, line %d: mtx_owned(&sched_lock) == %d\n", __FILE__, __LINE__, mtx_owned(&sched_lock));
+ printf("At %s, line %d: mtx_owned(&Giant) == %d, mtx_owned(&sched_lock) == %d\n", __FILE__, __LINE__, mtx_owned(&Giant), mtx_owned(&sched_lock));
#endif
- random_set_wakeup((int *)status, 0);
for (pl = 0; pl < 2; pl++)
yarrow_hash_init(&random_state.pool[pl].hash, NULL, 0);
@@ -148,9 +146,6 @@ random_kthread(void *status)
source->frac %= 1024;
free(event, M_TEMP);
- /* XXX abuse tsleep() to get at mi_switch() */
- /* tsleep(&harvestqueue, PUSER, "rndprc", 1); */
-
}
#ifdef DEBUG1
printf("Harvested %d events\n", queuecount);
@@ -177,7 +172,7 @@ random_kthread(void *status)
}
/* Is the thread scheduled for a shutdown? */
- if (random_kthread_control < 0) {
+ if (random_kthread_control != 0) {
if (!TAILQ_EMPTY(&harvestqueue)) {
#ifdef DEBUG
printf("Random cleaning extraneous events\n");
@@ -192,7 +187,8 @@ random_kthread(void *status)
#ifdef DEBUG
printf("Random kthread setting terminate\n");
#endif
- random_set_wakeup_exit((int *)status, -1, 0);
+ random_set_wakeup_exit(&random_kthread_control);
+ /* NOTREACHED */
break;
}
@@ -223,13 +219,13 @@ random_init(void)
mtx_init(&random_harvest_mtx, "random harvest", MTX_DEF);
/* Start the hash/reseed thread */
- error = kthread_create(random_kthread, &random_kthread_status,
+ error = kthread_create(random_kthread, NULL,
&random_kthread_proc, RFHIGHPID, "random");
if (error != 0)
return error;
/* Register the randomness harvesting routine */
- random_init_harvester(random_harvest_internal);
+ random_init_harvester(random_harvest_internal, read_random_real);
#ifdef DEBUG
printf("Random initalise finish\n");
@@ -253,9 +249,11 @@ random_deinit(void)
#endif
/* Command the hash/reseed thread to end and wait for it to finish */
+ mtx_enter(&random_harvest_mtx, MTX_DEF);
random_kthread_control = -1;
- while (random_kthread_status != -1)
- tsleep(&random_kthread_status, PUSER, "rndend", hz);
+ msleep((void *)&random_kthread_control, &random_harvest_mtx, PUSER,
+ "rndend", 0);
+ mtx_exit(&random_harvest_mtx, MTX_DEF);
#ifdef DEBUG
printf("Random deinitalise removing mutexes\n");
@@ -364,10 +362,16 @@ reseed(int fastslow)
printf("Reseed finish\n");
#endif
+ if (!random_state.seeded) {
+ random_state.seeded = 1;
+ selwakeup(&random_state.rsel);
+ wakeup(&random_state);
+ }
+
}
u_int
-read_random(void *buf, u_int count)
+read_random_real(void *buf, u_int count)
{
static u_int64_t genval;
static int cur = 0;
@@ -430,19 +434,19 @@ write_random(void *buf, u_int count)
u_int i;
struct timespec timebuf;
- /* arbitrarily break the input up into 8-byte chunks */
- for (i = 0; i < count; i += 8) {
+ /* arbitrarily break the input up into HARVESTSIZE chunks */
+ for (i = 0; i < count; i += HARVESTSIZE) {
nanotime(&timebuf);
- random_harvest_internal(&timebuf, (char *)buf + i, 8, 0, 0,
+ random_harvest_internal(&timebuf, (char *)buf + i, HARVESTSIZE, 0, 0,
RANDOM_WRITE);
}
/* Maybe the loop iterated at least once */
if (i > count)
- i -= 8;
+ i -= HARVESTSIZE;
- /* Get the last bytes even if the input length is not a multiple of 8 */
- count %= 8;
+ /* Get the last bytes even if the input length is not a multiple of HARVESTSIZE */
+ count %= HARVESTSIZE;
if (count) {
nanotime(&timebuf);
random_harvest_internal(&timebuf, (char *)buf + i, count, 0, 0,
@@ -486,7 +490,6 @@ random_harvest_internal(struct timespec *timep, void *entropy, u_int count,
u_int bits, u_int frac, enum esource origin)
{
struct harvest *event;
- u_int64_t entropy_buf;
#if 0
#ifdef DEBUG
@@ -501,8 +504,8 @@ random_harvest_internal(struct timespec *timep, void *entropy, u_int count,
event->time = *timep;
/* the harvested entropy */
- count = count > sizeof(entropy_buf)
- ? sizeof(entropy_buf)
+ count = count > sizeof(event->entropy)
+ ? sizeof(event->entropy)
: count;
memcpy(event->entropy, entropy, count);
diff --git a/sys/dev/random/yarrow.h b/sys/dev/random/yarrow.h
index a81fa1fc904e..4bf97fdef33e 100644
--- a/sys/dev/random/yarrow.h
+++ b/sys/dev/random/yarrow.h
@@ -36,16 +36,18 @@
#define ENTROPYBIN 256 /* buckets to harvest entropy events */
#define TIMEBIN 16 /* max value for Pt/t */
+#define HARVESTSIZE 16 /* max size of each harvested entropy unit */
+
#define FAST 0
#define SLOW 1
int random_init(void);
void random_deinit(void);
-void random_init_harvester(void (*)(struct timespec *, void *, u_int, u_int, u_int, enum esource));
+void random_init_harvester(void (*)(struct timespec *, void *, u_int, u_int, u_int, enum esource), u_int (*)(void *, u_int));
void random_deinit_harvester(void);
-void random_set_wakeup(int *, int);
-void random_set_wakeup_exit(int *, int, int);
+void random_set_wakeup_exit(void *);
+u_int read_random_real(void *, u_int);
void write_random(void *, u_int);
/* This is the beastie that needs protecting. It contains all of the
@@ -70,6 +72,8 @@ struct random_state {
struct yarrowhash hash; /* accumulated entropy */
} pool[2]; /* pool[0] is fast, pool[1] is slow */
int which; /* toggle - shows the current insertion pool */
+ int seeded; /* 0 until first reseed, then 1 */
+ struct selinfo rsel; /* For poll(2) */
};
extern struct random_state random_state;