Date: Sun, 17 Nov 2013 23:43:50 +0000 (UTC) From: Mark Murray <markm@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r258288 - projects/random_number_generator/sys/dev/random Message-ID: <201311172343.rAHNho7R020423@svn.freebsd.org>
index | next in thread | raw e-mail
Author: markm Date: Sun Nov 17 23:43:50 2013 New Revision: 258288 URL: http://svnweb.freebsd.org/changeset/base/258288 Log: Snapshot of WIP. Big refactor of the random_adaptors code to remove unnecessary layering. Also Yet Another Big Sweep Of Old code, essentially a rewrite of anything dodgy looking with my mind on efficiency. Some excess code is removed, and block copies are eliminated where possible. Locking is broken. This will be fixed in a follow-up. Modified: projects/random_number_generator/sys/dev/random/dummy_rng.c projects/random_number_generator/sys/dev/random/ivy.c projects/random_number_generator/sys/dev/random/live_entropy_sources.c projects/random_number_generator/sys/dev/random/live_entropy_sources.h projects/random_number_generator/sys/dev/random/nehemiah.c projects/random_number_generator/sys/dev/random/random_adaptors.c projects/random_number_generator/sys/dev/random/random_adaptors.h projects/random_number_generator/sys/dev/random/random_harvestq.c projects/random_number_generator/sys/dev/random/random_harvestq.h projects/random_number_generator/sys/dev/random/randomdev.c projects/random_number_generator/sys/dev/random/randomdev.h projects/random_number_generator/sys/dev/random/randomdev_soft.c projects/random_number_generator/sys/dev/random/randomdev_soft.h projects/random_number_generator/sys/dev/random/yarrow.c projects/random_number_generator/sys/dev/random/yarrow.h Modified: projects/random_number_generator/sys/dev/random/dummy_rng.c ============================================================================== --- projects/random_number_generator/sys/dev/random/dummy_rng.c Sun Nov 17 23:28:10 2013 (r258287) +++ projects/random_number_generator/sys/dev/random/dummy_rng.c Sun Nov 17 23:43:50 2013 (r258288) @@ -28,94 +28,66 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_random.h" + #include <sys/param.h> +#include <sys/conf.h> #include <sys/fcntl.h> #include <sys/kernel.h> #include <sys/lock.h> #include <sys/malloc.h> -#include <sys/mutex.h> #include <sys/random.h> #include <sys/syslog.h> #include <sys/systm.h> -#include <sys/time.h> #include <dev/random/randomdev.h> #include <dev/random/random_adaptors.h> -static struct mtx dummy_random_mtx; - -/* If no entropy device is loaded, don't spam the console with warnings */ -static int warned = 0; - -/* Used to fake out unused random calls in random_adaptor */ -static void -random_null_func(void) -{ -} - static int -dummy_random_poll(int events __unused, struct thread *td __unused) +dummy_random_zero(void) { return (0); } -static int -dummy_random_block(int flag) -{ - int error = 0; - - mtx_lock(&dummy_random_mtx); - - /* Blocking logic */ - while (!error) { - if (flag & O_NONBLOCK) - error = EWOULDBLOCK; - else { - printf("random: dummy device blocking on read.\n"); - error = msleep(&dummy_random_block, - &dummy_random_mtx, - PUSER | PCATCH, "block", 0); - } - } - mtx_unlock(&dummy_random_mtx); - - return (error); -} - static void -dummy_random_init(void) +dummy_random(void) { - - mtx_init(&dummy_random_mtx, "sleep mtx for dummy_random", - NULL, MTX_DEF); } +/* ARGSUSED */ static void -dummy_random_deinit(void) +dummy_random_init(struct mtx *mtx __unused) { - mtx_destroy(&dummy_random_mtx); + randomdev_init_reader(dummy_random_read_phony); } /* This is used only by the internal read_random(9) call, and then only * if no entropy processor is loaded. * - * DO NOT, REPEAT, DO NOT add this to the "struct random_adaptor" below! - * * Make a token effort to provide _some_ kind of output. No warranty of * the quality of this output is made, mainly because its lousy. * + * This is only used by the internal read_random(9) call when no other + * adaptor is active. + * + * It has external scope due to the way things work in + * randomdev_[de]init_reader() that the rest of the world doesn't need to + * know about. + * * Caveat Emptor. */ -int -dummy_random_read_phony(void *buf, int count) +u_int +dummy_random_read_phony(void *buf, u_int count) { + /* If no entropy device is loaded, don't spam the console with warnings */ + static int warned = 0; u_long randval; int size, i; if (!warned) { - log(LOG_WARNING, "random device not loaded; using insecure pseudo-random number generator\n"); + log(LOG_WARNING, "random device not loaded/active; using insecure pseudo-random number generator\n"); warned = 1; } @@ -132,13 +104,12 @@ dummy_random_read_phony(void *buf, int c } struct random_adaptor randomdev_dummy = { - .ra_ident = "Dummy entropy device", - .ra_init = dummy_random_init, - .ra_deinit = dummy_random_deinit, - .ra_block = dummy_random_block, - .ra_poll = dummy_random_poll, - .ra_read = (random_adaptor_read_func_t *)random_null_func, - .ra_reseed = (random_adaptor_reseed_func_t *)random_null_func, - .ra_seeded = 0, /* This device can never be seeded */ + .ra_ident = "Dummy", .ra_priority = 1, /* Bottom priority, so goes to last position */ + .ra_reseed = dummy_random, + .ra_seeded = (random_adaptor_seeded_func_t *)dummy_random_zero, + .ra_read = (random_adaptor_read_func_t *)dummy_random_zero, + .ra_write = (random_adaptor_write_func_t *)dummy_random_zero, + .ra_init = dummy_random_init, + .ra_deinit = dummy_random, }; Modified: projects/random_number_generator/sys/dev/random/ivy.c ============================================================================== --- projects/random_number_generator/sys/dev/random/ivy.c Sun Nov 17 23:28:10 2013 (r258287) +++ projects/random_number_generator/sys/dev/random/ivy.c Sun Nov 17 23:43:50 2013 (r258288) @@ -52,10 +52,10 @@ __FBSDID("$FreeBSD$"); #define RETRY_COUNT 10 -static int random_ivy_read(void *, int); +static u_int random_ivy_read(void *, u_int); static struct live_entropy_source random_ivy = { - .les_ident = "Hardware, Intel IvyBridge+ RNG", + .les_ident = "Intel IvyBridge+ RNG", .les_source = RANDOM_PURE_RDRAND, .les_read = random_ivy_read }; @@ -85,15 +85,17 @@ ivy_rng_store(long *buf) #endif } -static int -random_ivy_read(void *buf, int c) +/* It is specifically allowed that buf is a multiple of sizeof(long) */ +static u_int +random_ivy_read(void *buf, u_int c) { long *b; - int count; + u_int count; KASSERT(c % sizeof(long) == 0, ("partial read %d", c)); - for (b = buf, count = c; count > 0; count -= sizeof(long), b++) { - if (ivy_rng_store(b) == 0) + b = buf; + for (count = c; count > 0; count -= sizeof(long)) { + if (ivy_rng_store(b++) == 0) break; } return (c - count); Modified: projects/random_number_generator/sys/dev/random/live_entropy_sources.c ============================================================================== --- projects/random_number_generator/sys/dev/random/live_entropy_sources.c Sun Nov 17 23:28:10 2013 (r258287) +++ projects/random_number_generator/sys/dev/random/live_entropy_sources.c Sun Nov 17 23:43:50 2013 (r258288) @@ -28,6 +28,8 @@ #include <sys/param.h> __FBSDID("$FreeBSD$"); +#include "opt_random.h" + #include <sys/kernel.h> #include <sys/libkern.h> #include <sys/lock.h> @@ -52,7 +54,7 @@ __FBSDID("$FreeBSD$"); /* * The les_lock protects the consistency of the "struct les_head les_sources" */ -static struct sx les_lock; /* need a sleepable lock */ +static struct sx les_lock; /* Need a sleepable lock for the sbuf/sysctl stuff. */ LIST_HEAD(les_head, live_entropy_sources); static struct les_head les_sources = LIST_HEAD_INITIALIZER(les_sources); @@ -124,7 +126,6 @@ live_entropy_source_handler(SYSCTL_HANDL * * BEWARE!!! * This function runs inside the RNG thread! Don't do anything silly! - * Remember that we are NOT holding harvest_mtx on entry! */ /* XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle * counters are built in, but on older hardware it will do a real time clock @@ -135,7 +136,8 @@ live_entropy_sources_feed(void) { static struct harvest_event event; struct live_entropy_sources *lles; - int i, n, read_rate; + int i, read_rate; + u_int n; sx_slock(&les_lock); @@ -156,7 +158,7 @@ live_entropy_sources_feed(void) /* This *must* be quick, since it's a live entropy source. */ n = lles->lles_rsource->les_read(event.he_entropy, HARVESTSIZE); KASSERT((n > 0 && n <= HARVESTSIZE), ("very bad return from les_read (= %d) in %s", n, __func__)); - memset(event.he_entropy + n, 0, HARVESTSIZE - (u_int)n); + memset(event.he_entropy + n, 0, HARVESTSIZE - n); /* Do the actual entropy insertion */ harvest_process_event(&event); Modified: projects/random_number_generator/sys/dev/random/live_entropy_sources.h ============================================================================== --- projects/random_number_generator/sys/dev/random/live_entropy_sources.h Sun Nov 17 23:28:10 2013 (r258287) +++ projects/random_number_generator/sys/dev/random/live_entropy_sources.h Sun Nov 17 23:43:50 2013 (r258288) @@ -30,6 +30,8 @@ #ifndef SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED #define SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED +typedef u_int random_live_read_func_t(void *, u_int); + /* * Live entropy source is a source of entropy that can provide * specified or approximate amount of entropy immediately upon request or within @@ -38,7 +40,7 @@ struct live_entropy_source { const char *les_ident; enum random_entropy_source les_source; - random_adaptor_read_func_t *les_read; + random_live_read_func_t *les_read; }; struct live_entropy_sources { Modified: projects/random_number_generator/sys/dev/random/nehemiah.c ============================================================================== --- projects/random_number_generator/sys/dev/random/nehemiah.c Sun Nov 17 23:28:10 2013 (r258287) +++ projects/random_number_generator/sys/dev/random/nehemiah.c Sun Nov 17 23:43:50 2013 (r258288) @@ -50,10 +50,10 @@ __FBSDID("$FreeBSD$"); static void random_nehemiah_init(void); static void random_nehemiah_deinit(void); -static int random_nehemiah_read(void *, int); +static u_int random_nehemiah_read(void *, u_int); static struct live_entropy_source random_nehemiah = { - .les_ident = "Hardware, VIA Nehemiah Padlock RNG", + .les_ident = "VIA Nehemiah Padlock RNG", .les_source = RANDOM_PURE_NEHEMIAH, .les_read = random_nehemiah_read }; @@ -100,8 +100,9 @@ random_nehemiah_deinit(void) fpu_kern_free_ctx(fpu_ctx_save); } -static int -random_nehemiah_read(void *buf, int c) +/* It is specifically allowed that buf is a multiple of sizeof(long) */ +static u_int +random_nehemiah_read(void *buf, u_int c) { uint8_t *b; size_t count, ret; Modified: projects/random_number_generator/sys/dev/random/random_adaptors.c ============================================================================== --- projects/random_number_generator/sys/dev/random/random_adaptors.c Sun Nov 17 23:28:10 2013 (r258287) +++ projects/random_number_generator/sys/dev/random/random_adaptors.c Sun Nov 17 23:43:50 2013 (r258288) @@ -29,7 +29,11 @@ #include <sys/param.h> __FBSDID("$FreeBSD$"); +#include "opt_random.h" + #include <sys/systm.h> +#include <sys/conf.h> +#include <sys/fcntl.h> #include <sys/kernel.h> #include <sys/kthread.h> #include <sys/libkern.h> @@ -40,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <sys/queue.h> #include <sys/random.h> #include <sys/sbuf.h> +#include <sys/selinfo.h> #include <sys/sx.h> #include <sys/sysctl.h> #include <sys/uio.h> @@ -48,25 +53,105 @@ __FBSDID("$FreeBSD$"); #include <dev/random/randomdev.h> #include <dev/random/random_adaptors.h> -/* These are the data structures and associated items that need to be locked against - * "under-the-feet" changes. +/* The random_adaptors_lock protects random_adaptors_list and friends and random_adaptor. + * We need a sleepable lock for uiomove/block/poll/sbuf/sysctl. */ -static struct sx random_adaptors_lock; /* need a sleepable lock */ - +static struct sx random_adaptors_lock; LIST_HEAD(adaptors_head, random_adaptors); static struct adaptors_head random_adaptors_list = LIST_HEAD_INITIALIZER(random_adaptors_list); static struct random_adaptor *random_adaptor = NULL; /* Currently active adaptor */ -/* End of data items requiring adaptor lock protection */ +/* End of data items requiring random_adaptors_lock protection */ -/* The rate mutex protects the consistency of the read-rate logic. */ -struct mtx rate_mtx; +/* The random_rate_mtx mutex protects the consistency of the read-rate logic. */ +struct mtx random_rate_mtx; int random_adaptor_read_rate_cache; -/* End of data items requiring rate mutex protection */ +/* End of data items requiring random_rate_mtx mutex protection */ + +/* The random_reseed_mtx mutex protects seeding and polling/blocking. + * This is passed into the software entropy hasher/processor. + */ +struct mtx random_reseed_mtx; +/* End of data items requiring random_reseed_mtx mutex protection */ -MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); +static struct selinfo rsel; + +/* Utility routine to change active adaptor when the random_adaptors_list + * gets modified. + * + * Walk a list of registered random(4) adaptors and pick either a requested + * one or the highest priority one, whichever comes first. Panic on failure + * as the fallback must always be the "dummy" adaptor. + */ +static void +random_adaptor_choose(void) +{ + char rngs[128], *token, *cp; + struct random_adaptors *rra, *rrai; + struct random_adaptor *random_adaptor_previous; + int primax; + + /* We are going to be messing with random_adaptor. + * Exclusive lock is mandatory. + */ + sx_assert(&random_adaptors_lock, SA_XLOCKED); + + random_adaptor_previous = random_adaptor; + + random_adaptor = NULL; + if (TUNABLE_STR_FETCH("kern.random.active_adaptor", rngs, sizeof(rngs))) { + cp = rngs; -static void random_adaptor_choose(void); + while ((token = strsep(&cp, ",")) != NULL) { + LIST_FOREACH(rra, &random_adaptors_list, rra_entries) + if (strcmp(rra->rra_name, token) == 0) { + random_adaptor = rra->rra_ra; + break; + } + if (random_adaptor != NULL) { + printf("random: selecting requested adaptor <%s>\n", + random_adaptor->ra_ident); + break; + } + else + printf("random: requested adaptor <%s> not available\n", + token); + } + } + primax = 0; + if (random_adaptor == NULL) { + /* + * Fall back to the highest priority item on the available + * RNG list. + */ + LIST_FOREACH(rrai, &random_adaptors_list, rra_entries) { + if (rrai->rra_ra->ra_priority >= primax) { + random_adaptor = rrai->rra_ra; + primax = rrai->rra_ra->ra_priority; + } + } + if (random_adaptor != NULL) + printf("random: selecting highest priority adaptor <%s>\n", + random_adaptor->ra_ident); + } + + KASSERT(random_adaptor != NULL, ("adaptor not found")); + + /* If we are changing adaptors, deinit the old and init the new. */ + if (random_adaptor != random_adaptor_previous) { +#ifdef RANDOM_DEBUG + printf("random: %s - changing from %s to %s\n", __func__, + (random_adaptor_previous == NULL ? "NULL" : random_adaptor_previous->ra_ident), + random_adaptor->ra_ident); +#endif + if (random_adaptor_previous != NULL) + (random_adaptor_previous->ra_deinit)(); + (random_adaptor->ra_init)(&random_reseed_mtx); + } +} + + +/* XXX: FIX!! Make sure we are not inserting a duplicate */ void random_adaptor_register(const char *name, struct random_adaptor *ra) { @@ -79,12 +164,8 @@ random_adaptor_register(const char *name rra->rra_ra = ra; sx_xlock(&random_adaptors_lock); - - /* XXX: FIX!! Make sure we are not inserting a duplicate */ LIST_INSERT_HEAD(&random_adaptors_list, rra, rra_entries); - random_adaptor_choose(); - sx_xunlock(&random_adaptors_lock); KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); @@ -99,80 +180,133 @@ random_adaptor_deregister(const char *na KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); sx_xlock(&random_adaptors_lock); - LIST_FOREACH(rra, &random_adaptors_list, rra_entries) if (strcmp(rra->rra_name, name) == 0) { LIST_REMOVE(rra, rra_entries); break; } - random_adaptor_choose(); - /* It is conceivable that there is no active random adaptor here, - * e.g. at shutdown. - */ - sx_xunlock(&random_adaptors_lock); - if (rra != NULL) - free(rra, M_ENTROPY); + free(rra, M_ENTROPY); } +/* + * Per-instance structure. + * + * List of locks + * XXX: FIX!! + */ +struct random_adaptor_softc { + int oink; + int tweet; +}; + +static void +random_adaptor_dtor(void *data) +{ + struct random_adaptor_softc *ras = data; + + free(ras, M_ENTROPY); +} + +/* ARGSUSED */ int -random_adaptor_block(int flag) +random_adaptor_open(struct cdev *dev __unused, int flags, int mode __unused, struct thread *td __unused) { - int ret; + struct random_adaptor_softc *ras; KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); - sx_slock(&random_adaptors_lock); + ras = malloc(sizeof(struct random_adaptor_softc), M_ENTROPY, M_WAITOK|M_ZERO); + /* XXX: FIX!! Set up softc here */ - ret = random_adaptor->ra_block(flag); + devfs_set_cdevpriv(ras, random_adaptor_dtor); - sx_sunlock(&random_adaptors_lock); + /* Give the source a chance to do some pre-read/write startup */ + if (flags & FREAD) { + sx_slock(&random_adaptors_lock); + (random_adaptor->ra_read)(NULL, 0); + sx_sunlock(&random_adaptors_lock); + } else if (flags & FWRITE) { + sx_slock(&random_adaptors_lock); + (random_adaptor->ra_write)(NULL, 0); + sx_sunlock(&random_adaptors_lock); + } + + return (0); +} - return ret; +/* ARGSUSED */ +int +random_adaptor_close(struct cdev *dev __unused, int flags, int fmt __unused, struct thread *td __unused) +{ + + KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); + + /* Give the source a chance to do some post-read/write shutdown */ + if (flags & FREAD) { + sx_slock(&random_adaptors_lock); + (random_adaptor->ra_read)(NULL, 1); + sx_sunlock(&random_adaptors_lock); + } else if (flags & FWRITE) { + sx_slock(&random_adaptors_lock); + (random_adaptor->ra_write)(NULL, 1); + sx_sunlock(&random_adaptors_lock); + } + + return (0); } +/* ARGSUSED */ int -random_adaptor_read(struct uio *uio, int flag) +random_adaptor_read(struct cdev *dev __unused, struct uio *uio, int flags __unused) { - int c, error = 0; void *random_buf; + int c, error; + u_int npages; + struct random_adaptor_softc *ras; KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); - /* The read-rate stuff is a *VERY* crude measure of the instantaneous read rate, designed - * to increase the use of 'live' entropy sources when lots of reads are done. - */ - mtx_lock(&rate_mtx); - random_adaptor_read_rate_cache += (int)((uio->uio_resid + PAGE_SIZE + 1)/PAGE_SIZE); - mtx_unlock(&rate_mtx); + error = devfs_get_cdevpriv((void **)&ras); + if (error == 0) { - sx_slock(&random_adaptors_lock); + sx_slock(&random_adaptors_lock); - /* Blocking logic */ - if (random_adaptor->ra_seeded) - error = (random_adaptor->ra_block)(flag); - - /* The actual read */ - if (!error) { - - random_buf = (void *)malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); - - while (uio->uio_resid > 0 && !error) { - c = MIN(uio->uio_resid, PAGE_SIZE); - c = (random_adaptor->ra_read)(random_buf, c); - error = uiomove(random_buf, c, uio); + /* Blocking logic */ + mtx_lock(&random_reseed_mtx); + while (!random_adaptor->ra_seeded() && !error) { + if (flags & O_NONBLOCK) + error = EWOULDBLOCK; + else + error = msleep(&random_adaptor, &random_reseed_mtx, PUSER | PCATCH, "block", 0); } - /* Finished reading; let the source know so it can do some - * optional housekeeping */ - (random_adaptor->ra_read)(NULL, 0); + mtx_unlock(&random_reseed_mtx); - free(random_buf, M_ENTROPY); + /* The actual read */ + if (!error) { + /* The read-rate stuff is a *VERY* crude indication of the instantaneous read rate, + * designed to increase the use of 'live' entropy sources when lots of reads are done. + */ + mtx_lock(&random_rate_mtx); + npages = (uio->uio_resid + PAGE_SIZE - 1)/PAGE_SIZE; + random_adaptor_read_rate_cache += npages; + random_adaptor_read_rate_cache = MIN(random_adaptor_read_rate_cache, 32); + mtx_unlock(&random_rate_mtx); + + random_buf = (void *)malloc(npages*PAGE_SIZE, M_ENTROPY, M_WAITOK); + while (uio->uio_resid > 0 && !error) { + c = MIN(uio->uio_resid, npages*PAGE_SIZE); + (random_adaptor->ra_read)(random_buf, c); + error = uiomove(random_buf, c, uio); + } + free(random_buf, M_ENTROPY); + } - } + sx_sunlock(&random_adaptors_lock); - sx_sunlock(&random_adaptors_lock); + } return (error); } @@ -182,98 +316,83 @@ random_adaptor_read_rate(void) { int ret; - mtx_lock(&rate_mtx); - ret = random_adaptor_read_rate_cache = random_adaptor_read_rate_cache ? random_adaptor_read_rate_cache%32 + 1 : 1; - mtx_unlock(&rate_mtx); + KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); + + mtx_lock(&random_rate_mtx); + ret = random_adaptor_read_rate_cache; + mtx_unlock(&random_rate_mtx); return (ret); } +/* ARGSUSED */ int -random_adaptor_poll(int events, struct thread *td) +random_adaptor_write(struct cdev *dev __unused, struct uio *uio, int flags __unused) { - int revents = 0; + int error; + struct random_adaptor_softc *ras; - sx_slock(&random_adaptors_lock); + KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); - if (events & (POLLIN | POLLRDNORM)) { - if (random_adaptor->ra_seeded) - revents = events & (POLLIN | POLLRDNORM); - else - revents = (random_adaptor->ra_poll)(events, td); + sx_slock(&random_adaptors_lock); + error = devfs_get_cdevpriv((void **)&ras); + if (error == 0) { + /* We used to allow this to insert userland entropy. + * We don't any more because (1) this so-called entropy + * is usually lousy and (b) its vaguely possible to + * mess with entropy harvesting by overdoing a write. + * Now we just ignore input like /dev/null does. + */ + /* XXX: FIX!! Now that RWFILE is gone, we need to get this back. + * ALSO: See devfs_get_cdevpriv(9) and friends for ways to build per-session nodes. + */ + uio->uio_resid = 0; + /* c = (random_adaptor->ra_write)(random_buf, c); */ } - sx_sunlock(&random_adaptors_lock); - return (revents); + return (error); } -/* - * Walk a list of registered random(4) adaptors and pick either a requested - * one or the highest priority one, whichever comes first. Panic on failure - * as the fallback must be the "dummy" adaptor. - */ -static void -random_adaptor_choose(void) +/* ARGSUSED */ +int +random_adaptor_poll(struct cdev *dev __unused, int events, struct thread *td __unused) { - char rngs[128], *token, *cp; - struct random_adaptors *rra, *rrai; - struct random_adaptor *random_adaptor_previous; - int primax; - - /* We are going to be messing with random_adaptor. - * Exclusive lock is mandatory. - */ - sx_assert(&random_adaptors_lock, SA_XLOCKED); + struct random_adaptor_softc *ras; - random_adaptor_previous = random_adaptor; + KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); - random_adaptor = NULL; - if (TUNABLE_STR_FETCH("kern.random.active_adaptor", rngs, sizeof(rngs))) { - cp = rngs; + if (devfs_get_cdevpriv((void **)&ras) != 0) + return (events & + (POLLHUP|POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM)); - while ((token = strsep(&cp, ",")) != NULL) { - LIST_FOREACH(rra, &random_adaptors_list, rra_entries) - if (strcmp(rra->rra_name, token) == 0) { - random_adaptor = rra->rra_ra; - break; - } - if (random_adaptor != NULL) { - printf("random: selecting requested adaptor <%s>\n", - random_adaptor->ra_ident); - break; - } - else - printf("random: requested adaptor <%s> not available\n", - token); - } + sx_slock(&random_adaptors_lock); + mtx_lock(&random_reseed_mtx); + if (events & (POLLIN | POLLRDNORM)) { + if (random_adaptor->ra_seeded()) + events &= (POLLIN | POLLRDNORM); + else + selrecord(td, &rsel); } + mtx_unlock(&random_reseed_mtx); + sx_sunlock(&random_adaptors_lock); - primax = 0; - if (random_adaptor == NULL) { - /* - * Fall back to the highest priority item on the available - * RNG list. - */ - LIST_FOREACH(rrai, &random_adaptors_list, rra_entries) { - if (rrai->rra_ra->ra_priority >= primax) { - random_adaptor = rrai->rra_ra; - primax = rrai->rra_ra->ra_priority; - } - } - if (random_adaptor != NULL) - printf("random: selecting highest priority adaptor <%s>\n", - random_adaptor->ra_ident); - } + return (events); +} - KASSERT(random_adaptor != NULL, ("adaptor not found")); +/* This will be called by the entropy processor when it seeds itself and becomes secure */ +void +random_adaptor_unblock(void) +{ - /* If we are changing adaptors, deinit the old and init the new. */ - if (random_adaptor != random_adaptor_previous) { - if (random_adaptor_previous != NULL) - (random_adaptor_previous->ra_deinit)(); - (random_adaptor->ra_init)(); - } + mtx_assert(&random_reseed_mtx, MA_OWNED); + + selwakeuppri(&rsel, PUSER); + wakeup(&random_adaptor); + printf("random: unblocking device.\n"); + + /* Do arc4random(9) a favour while we are about it. */ + (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, ARC4_ENTR_HAVE); } static int @@ -284,9 +403,7 @@ random_sysctl_adaptors_handler(SYSCTL_HA int error, count; sx_slock(&random_adaptors_lock); - sbuf_new_for_sysctl(&sbuf, NULL, 64, req); - count = 0; LIST_FOREACH(rra, &random_adaptors_list, rra_entries) sbuf_printf(&sbuf, "%s%s(%d)", @@ -294,7 +411,6 @@ random_sysctl_adaptors_handler(SYSCTL_HA error = sbuf_finish(&sbuf); sbuf_delete(&sbuf); - sx_sunlock(&random_adaptors_lock); return (error); @@ -310,19 +426,14 @@ random_sysctl_active_adaptor_handler(SYS KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); sx_slock(&random_adaptors_lock); - sbuf_new_for_sysctl(&sbuf, NULL, 16, req); - LIST_FOREACH(rra, &random_adaptors_list, rra_entries) if (rra->rra_ra == random_adaptor) { sbuf_cat(&sbuf, rra->rra_name); break; } - - error = sbuf_finish(&sbuf); sbuf_delete(&sbuf); - sx_sunlock(&random_adaptors_lock); return (error); @@ -344,30 +455,37 @@ random_adaptors_init(void *unused __unus "Active Random Number Generator Adaptor"); sx_init(&random_adaptors_lock, "random_adaptors"); - mtx_init(&rate_mtx, "read rate mutex", NULL, MTX_DEF); - /* This dummy "thing" is not a module by itself, but part of the + mtx_init(&random_rate_mtx, "read rate mutex", NULL, MTX_DEF); + mtx_init(&random_reseed_mtx, "read rate mutex", NULL, MTX_DEF); + + /* The dummy adaptor is not a module by itself, but part of the * randomdev module. */ random_adaptor_register("dummy", &randomdev_dummy); } +SYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, + random_adaptors_init, NULL); /* ARGSUSED */ static void random_adaptors_deinit(void *unused __unused) { - /* Don't do this! Panic will follow. */ + /* Don't do this! Panic will surely follow! */ /* random_adaptor_deregister("dummy"); */ - mtx_destroy(&rate_mtx); + mtx_destroy(&random_reseed_mtx); + mtx_destroy(&random_rate_mtx); + sx_destroy(&random_adaptors_lock); } +SYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, + random_adaptors_deinit, NULL); /* * First seed. * * NB! NB! NB! - * * NB! NB! NB! * * It turns out this is bloody dangerous. I was fiddling with code elsewhere @@ -376,6 +494,9 @@ random_adaptors_deinit(void *unused __un * As crap randomness is not directly distinguishable from good randomness, this * could have gone unnoticed for quite a while. * + * NB! NB! NB! + * NB! NB! NB! + * * Very luckily, the probe-time entropy is very nearly good enough to cause a * first seed all of the time, and the default settings for other entropy * harvesting causes a proper, safe, first seed (unblock) in short order after that. @@ -394,9 +515,7 @@ random_adaptors_seed(void *unused __unus KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__)); sx_slock(&random_adaptors_lock); - random_adaptor->ra_reseed(); - sx_sunlock(&random_adaptors_lock); arc4rand(NULL, 0, 1); @@ -404,8 +523,3 @@ random_adaptors_seed(void *unused __unus SYSINIT(random_seed, SI_SUB_INTRINSIC_POST, SI_ORDER_LAST, random_adaptors_reseed, NULL); #endif /* RANDOM_AUTOSEED */ - -SYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_SECOND, - random_adaptors_init, NULL); -SYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_SECOND, - random_adaptors_deinit, NULL); Modified: projects/random_number_generator/sys/dev/random/random_adaptors.h ============================================================================== --- projects/random_number_generator/sys/dev/random/random_adaptors.h Sun Nov 17 23:28:10 2013 (r258287) +++ projects/random_number_generator/sys/dev/random/random_adaptors.h Sun Nov 17 23:43:50 2013 (r258288) @@ -31,25 +31,22 @@ MALLOC_DECLARE(M_ENTROPY); -typedef void random_adaptor_init_func_t(void); +typedef void random_adaptor_init_func_t(struct mtx *); typedef void random_adaptor_deinit_func_t(void); - -typedef int random_adaptor_block_func_t(int); -typedef int random_adaptor_read_func_t(void *, int); -typedef int random_adaptor_poll_func_t(int, struct thread *); - +typedef void random_adaptor_read_func_t(uint8_t *, u_int); +typedef void random_adaptor_write_func_t(uint8_t *, u_int); +typedef int random_adaptor_seeded_func_t(void); typedef void random_adaptor_reseed_func_t(void); struct random_adaptor { const char *ra_ident; - int ra_seeded; - int ra_priority; + int ra_priority; random_adaptor_init_func_t *ra_init; random_adaptor_deinit_func_t *ra_deinit; - random_adaptor_block_func_t *ra_block; random_adaptor_read_func_t *ra_read; - random_adaptor_poll_func_t *ra_poll; + random_adaptor_write_func_t *ra_write; random_adaptor_reseed_func_t *ra_reseed; + random_adaptor_seeded_func_t *ra_seeded; }; struct random_adaptors { @@ -64,10 +61,13 @@ extern struct random_adaptor randomdev_d void random_adaptor_register(const char *, struct random_adaptor *); void random_adaptor_deregister(const char *); -int random_adaptor_block(int); -int random_adaptor_read(struct uio *, int); -int random_adaptor_poll(int, struct thread *); +int random_adaptor_open(struct cdev *, int, int, struct thread *); +int random_adaptor_read(struct cdev *, struct uio *, int); +int random_adaptor_write(struct cdev *, struct uio *, int); +int random_adaptor_close(struct cdev *, int, int, struct thread *); +int random_adaptor_poll(struct cdev *, int, struct thread *); int random_adaptor_read_rate(void); +void random_adaptor_unblock(void); #endif /* SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED */ Modified: projects/random_number_generator/sys/dev/random/random_harvestq.c ============================================================================== --- projects/random_number_generator/sys/dev/random/random_harvestq.c Sun Nov 17 23:28:10 2013 (r258287) +++ projects/random_number_generator/sys/dev/random/random_harvestq.c Sun Nov 17 23:43:50 2013 (r258288) @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/mutex.h> #include <sys/random.h> +#include <sys/sbuf.h> #include <sys/sysctl.h> #include <sys/unistd.h> @@ -52,6 +53,9 @@ __FBSDID("$FreeBSD$"); #include <dev/random/random_harvestq.h> #include <dev/random/live_entropy_sources.h> +/* List for the dynamic sysctls */ +static struct sysctl_ctx_list random_clist; + /* * How many events to queue up. We create this many items in * an 'empty' queue, then transfer them to the 'harvest' queue with @@ -64,7 +68,7 @@ __FBSDID("$FreeBSD$"); * The harvest mutex protects the consistency of the entropy Fifos and * empty fifo and other associated structures. */ -struct mtx harvest_mtx; +static struct mtx harvest_mtx; /* Lockable FIFO queue holding entropy buffers */ struct entropyfifo { @@ -83,6 +87,11 @@ u_int harvest_destination[ENTROPYSOURCE] /* Function called to process one harvested stochastic event */ void (*harvest_process_event)(struct harvest_event *); +/* Allow the sysadmin to select the broad category of + * entropy types to harvest. + */ +static u_int harvest_source_mask = ((1<<RANDOM_ENVIRONMENTAL_END) - 1); + /* Pool count is used by anything needing to know how many entropy * pools are currently being maintained. * This is of use to (e.g.) the live source feed where we need to give @@ -91,7 +100,7 @@ void (*harvest_process_event)(struct har int harvest_pool_count; /* <0 to end the kthread, 0 to let it run, 1 to flush the harvest queues */ -int random_kthread_control = 0; +static int random_kthread_control = 0; static struct proc *random_kthread_proc; @@ -153,12 +162,75 @@ random_kthread(void *arg __unused) } void +random_harvestq_flush(void) +{ + + /* Command a entropy queue flush and wait for it to finish */ + random_kthread_control = 1; + while (random_kthread_control) + pause("-", hz/10); + +#if 0 +#if defined(RANDOM_YARROW) + random_yarrow_reseed(); +#endif +#if defined(RANDOM_FORTUNA) + random_fortuna_reseed(); +#endif +#endif +} + +/* ARGSUSED */ +RANDOM_CHECK_UINT(harvestmask, 0, ((1<<RANDOM_ENVIRONMENTAL_END) - 1)); + +/* ARGSUSED */ +static int +random_print_harvestmask(SYSCTL_HANDLER_ARGS) +{ + struct sbuf sbuf; + int error, i; + + error = sysctl_wire_old_buffer(req, 0); + if (error == 0) { + sbuf_new_for_sysctl(&sbuf, NULL, 128, req); + for (i = 31; i >= 0; i--) *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201311172343.rAHNho7R020423>
