Index: stable/10/sys/dev/random/live_entropy_sources.c =================================================================== --- stable/10/sys/dev/random/live_entropy_sources.c (revision 295479) +++ stable/10/sys/dev/random/live_entropy_sources.c (revision 295480) @@ -1,195 +1,195 @@ /*- * Copyright (c) 2013 Arthur Mesh * Copyright (c) 2013 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "live_entropy_sources.h" LIST_HEAD(les_head, live_entropy_sources); static struct les_head sources = LIST_HEAD_INITIALIZER(sources); /* * The live_lock protects the consistency of the "struct les_head sources" */ static struct sx les_lock; /* need a sleepable lock */ void live_entropy_source_register(struct random_hardware_source *rsource) { struct live_entropy_sources *les; KASSERT(rsource != NULL, ("invalid input to %s", __func__)); les = malloc(sizeof(struct live_entropy_sources), M_ENTROPY, M_WAITOK); les->rsource = rsource; sx_xlock(&les_lock); LIST_INSERT_HEAD(&sources, les, entries); sx_xunlock(&les_lock); } void live_entropy_source_deregister(struct random_hardware_source *rsource) { struct live_entropy_sources *les = NULL; KASSERT(rsource != NULL, ("invalid input to %s", __func__)); sx_xlock(&les_lock); LIST_FOREACH(les, &sources, entries) if (les->rsource == rsource) { LIST_REMOVE(les, entries); break; } sx_xunlock(&les_lock); if (les != NULL) free(les, M_ENTROPY); } static int live_entropy_source_handler(SYSCTL_HANDLER_ARGS) { struct live_entropy_sources *les; int error, count; count = error = 0; sx_slock(&les_lock); if (LIST_EMPTY(&sources)) error = SYSCTL_OUT(req, "", 0); else { LIST_FOREACH(les, &sources, entries) { error = SYSCTL_OUT(req, ",", count++ ? 1 : 0); if (error) break; error = SYSCTL_OUT(req, les->rsource->ident, strlen(les->rsource->ident)); if (error) break; } } sx_sunlock(&les_lock); return (error); } static void live_entropy_sources_init(void *unused) { SYSCTL_PROC(_kern_random, OID_AUTO, live_entropy_sources, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, live_entropy_source_handler, "", "List of Active Live Entropy Sources"); sx_init(&les_lock, "live_entropy_sources"); } /* * Run through all "live" sources reading entropy for the given * number of rounds, which should be a multiple of the number * of entropy accumulation pools in use; 2 for Yarrow and 32 * for Fortuna. * * BEWARE!!! * This function runs inside the RNG thread! Don't do anything silly! * Remember that we are NOT holding harvest_mtx on entry! */ void live_entropy_sources_feed(int rounds, event_proc_f entropy_processor) { static struct harvest event; static uint8_t buf[HARVESTSIZE]; struct live_entropy_sources *les; int i, n; sx_slock(&les_lock); /* * Walk over all of live entropy sources, and feed their output * to the system-wide RNG. */ LIST_FOREACH(les, &sources, entries) { for (i = 0; i < rounds; i++) { /* * This should be quick, since it's a live entropy * source. */ /* FIXME: Whine loudly if this didn't work. */ n = les->rsource->read(buf, sizeof(buf)); n = MIN(n, HARVESTSIZE); event.somecounter = get_cyclecount(); event.size = n; event.bits = (n*8)/2; event.source = les->rsource->source; memcpy(event.entropy, buf, n); /* Do the actual entropy insertion */ entropy_processor(&event); } } sx_sunlock(&les_lock); } static void live_entropy_sources_deinit(void *unused) { sx_destroy(&les_lock); } -SYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, +SYSINIT(random_adaptors, SI_SUB_RANDOM, SI_ORDER_FIRST, live_entropy_sources_init, NULL); -SYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, +SYSUNINIT(random_adaptors, SI_SUB_RANDOM, SI_ORDER_FIRST, live_entropy_sources_deinit, NULL); Index: stable/10/sys/dev/random/live_entropy_sources.h =================================================================== --- stable/10/sys/dev/random/live_entropy_sources.h (revision 295479) +++ stable/10/sys/dev/random/live_entropy_sources.h (revision 295480) @@ -1,60 +1,60 @@ /*- * Copyright (c) 2013 Arthur Mesh * Copyright (c) 2013 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED #define SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED /* * Live entropy source is a source of entropy that can provide * specified or approximate amount of entropy immediately upon request or within * an acceptable amount of time. */ struct live_entropy_sources { LIST_ENTRY(live_entropy_sources) entries; /* list of providers */ struct random_hardware_source *rsource; /* associated random adaptor */ }; extern struct mtx live_mtx; void live_entropy_source_register(struct random_hardware_source *); void live_entropy_source_deregister(struct random_hardware_source *); void live_entropy_sources_feed(int, event_proc_f); #define LIVE_ENTROPY_SRC_MODULE(name, modevent, ver) \ static moduledata_t name##_mod = { \ #name, \ modevent, \ 0 \ }; \ - DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, \ + DECLARE_MODULE(name, name##_mod, SI_SUB_RANDOM, \ SI_ORDER_SECOND); \ MODULE_VERSION(name, ver); \ MODULE_DEPEND(name, random, 1, 1, 1); #endif /* SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED */ Index: stable/10/sys/dev/random/random_adaptors.c =================================================================== --- stable/10/sys/dev/random/random_adaptors.c (revision 295479) +++ stable/10/sys/dev/random/random_adaptors.c (revision 295480) @@ -1,251 +1,251 @@ /*- * Copyright (c) 2013 Arthur Mesh * Copyright (c) 2013 David E. O'Brien * Copyright (c) 2013 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include LIST_HEAD(adaptors_head, random_adaptors); static struct adaptors_head adaptors = LIST_HEAD_INITIALIZER(adaptors); static struct sx adaptors_lock; /* need a sleepable lock */ /* List for the dynamic sysctls */ static struct sysctl_ctx_list random_clist; struct random_adaptor *random_adaptor; MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); int random_adaptor_register(const char *name, struct random_adaptor *rsp) { struct random_adaptors *rpp; KASSERT(name != NULL && rsp != NULL, ("invalid input to %s", __func__)); rpp = malloc(sizeof(struct random_adaptors), M_ENTROPY, M_WAITOK); rpp->name = name; rpp->rsp = rsp; sx_xlock(&adaptors_lock); LIST_INSERT_HEAD(&adaptors, rpp, entries); sx_xunlock(&adaptors_lock); return (0); } struct random_adaptor * random_adaptor_get(const char *name) { struct random_adaptors *rpp; struct random_adaptor *rsp; rsp = NULL; sx_slock(&adaptors_lock); LIST_FOREACH(rpp, &adaptors, entries) if (strcmp(rpp->name, name) == 0) rsp = rpp->rsp; sx_sunlock(&adaptors_lock); return (rsp); } /* * Walk a list of registered random(4) adaptors and pick the last non-selected * one. * * If none are selected, use yarrow if available. */ void random_adaptor_choose(struct random_adaptor **adaptor) { char rngs[128], *token, *cp; struct random_adaptors *rppi, *ramax; unsigned primax; KASSERT(adaptor != NULL, ("pre-conditions failed")); *adaptor = NULL; if (TUNABLE_STR_FETCH("kern.random.active_adaptor", rngs, sizeof(rngs))) { cp = rngs; while ((token = strsep(&cp, ",")) != NULL) if ((*adaptor = random_adaptor_get(token)) != NULL) break; else if (bootverbose) printf("%s random adaptor is not available," " skipping\n", token); } primax = 0U; if (*adaptor == NULL) { /* * Fall back to the highest priority item on the available * RNG list. */ sx_slock(&adaptors_lock); ramax = NULL; LIST_FOREACH(rppi, &adaptors, entries) { if (rppi->rsp->priority >= primax) { ramax = rppi; primax = rppi->rsp->priority; } } if (ramax != NULL) *adaptor = ramax->rsp; sx_sunlock(&adaptors_lock); if (bootverbose && *adaptor) printf("Falling back to <%s> random adaptor\n", (*adaptor)->ident); } } static void random_adaptors_deinit(void *unused) { sx_destroy(&adaptors_lock); sysctl_ctx_free(&random_clist); } static int random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS) { struct random_adaptors *rpp; int error, count; count = error = 0; sx_slock(&adaptors_lock); if (LIST_EMPTY(&adaptors)) error = SYSCTL_OUT(req, "", 0); else { LIST_FOREACH(rpp, &adaptors, entries) { error = SYSCTL_OUT(req, ",", count++ ? 1 : 0); if (error) break; error = SYSCTL_OUT(req, rpp->name, strlen(rpp->name)); if (error) break; } } sx_sunlock(&adaptors_lock); return (error); } static int random_sysctl_active_adaptor_handler(SYSCTL_HANDLER_ARGS) { struct random_adaptor *rsp; struct random_adaptors *rpp; const char *name; int error; name = NULL; rsp = random_adaptor; if (rsp != NULL) { sx_slock(&adaptors_lock); LIST_FOREACH(rpp, &adaptors, entries) if (rpp->rsp == rsp) name = rpp->name; sx_sunlock(&adaptors_lock); } if (rsp == NULL || name == NULL) error = SYSCTL_OUT(req, "", 0); else error = SYSCTL_OUT(req, name, strlen(name)); return (error); } static void random_adaptors_init(void *unused) { SYSCTL_PROC(_kern_random, OID_AUTO, adaptors, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, random_sysctl_adaptors_handler, "", "Random Number Generator adaptors"); SYSCTL_PROC(_kern_random, OID_AUTO, active_adaptor, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, random_sysctl_active_adaptor_handler, "", "Active Random Number Generator Adaptor"); sx_init(&adaptors_lock, "random_adaptors"); } SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Random Number Generator"); -SYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, random_adaptors_init, +SYSINIT(random_adaptors, SI_SUB_RANDOM, SI_ORDER_FIRST, random_adaptors_init, NULL); -SYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, +SYSUNINIT(random_adaptors, SI_SUB_RANDOM, SI_ORDER_FIRST, random_adaptors_deinit, NULL); static void random_adaptors_reseed(void *unused) { (void)unused; if (random_adaptor != NULL) (*random_adaptor->reseed)(); arc4rand(NULL, 0, 1); } SYSINIT(random_reseed, SI_SUB_INTRINSIC_POST, SI_ORDER_SECOND, random_adaptors_reseed, NULL); Index: stable/10/sys/dev/random/random_adaptors.h =================================================================== --- stable/10/sys/dev/random/random_adaptors.h (revision 295479) +++ stable/10/sys/dev/random/random_adaptors.h (revision 295480) @@ -1,71 +1,71 @@ /*- * Copyright (c) 2013 Arthur Mesh * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED #define SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED #include MALLOC_DECLARE(M_ENTROPY); struct random_adaptors { LIST_ENTRY(random_adaptors) entries; /* list of providers */ const char *name; /* name of random adaptor */ struct random_adaptor *rsp; }; struct random_adaptor *random_adaptor_get(const char *); int random_adaptor_register(const char *, struct random_adaptor *); void random_adaptor_choose(struct random_adaptor **); extern struct random_adaptor *random_adaptor; /* * random_adaptor's should be registered prior to - * random module (SI_SUB_DRIVERS/SI_ORDER_MIDDLE) + * random module (SI_SUB_RANDOM/SI_ORDER_MIDDLE) */ #define RANDOM_ADAPTOR_MODULE(name, modevent, ver) \ static moduledata_t name##_mod = { \ #name, \ modevent, \ 0 \ }; \ - DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, \ + DECLARE_MODULE(name, name##_mod, SI_SUB_RANDOM, \ SI_ORDER_SECOND); \ MODULE_VERSION(name, ver); \ MODULE_DEPEND(name, random, 1, 1, 1); typedef void (*random_adaptor_attach_hook)(void *, struct random_adaptor *); EVENTHANDLER_DECLARE(random_adaptor_attach, random_adaptor_attach_hook); /* kern.random sysctls */ #ifdef SYSCTL_DECL /* from sysctl.h */ SYSCTL_DECL(_kern_random); #endif /* SYSCTL_DECL */ #endif /* SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED */ Index: stable/10/sys/dev/random/random_harvestq.c =================================================================== --- stable/10/sys/dev/random/random_harvestq.c (revision 295479) +++ stable/10/sys/dev/random/random_harvestq.c (revision 295480) @@ -1,322 +1,348 @@ /*- * Copyright (c) 2000-2013 Mark R V Murray * Copyright (c) 2013 Arthur Mesh * Copyright (c) 2004 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include "opt_random.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define RANDOM_FIFO_MAX 1024 /* How many events to queue up */ /* * The harvest mutex protects the consistency of the entropy fifos and * empty fifo and other associated structures. */ struct mtx harvest_mtx; /* Lockable FIFO queue holding entropy buffers */ struct entropyfifo { int count; STAILQ_HEAD(harvestlist, harvest) head; }; /* Empty entropy buffers */ static struct entropyfifo emptyfifo; /* Harvested entropy */ static struct entropyfifo harvestfifo; /* <0 to end the kthread, 0 to let it run, 1 to flush the harvest queues */ int random_kthread_control = 0; static struct proc *random_kthread_proc; +static event_proc_f random_cb; + #ifdef RANDOM_RWFILE static const char *entropy_files[] = { "/entropy", NULL }; #endif /* Deal with entropy cached externally if this is present. * Lots of policy may eventually arrive in this function. * Called after / is mounted. */ static void random_harvestq_cache(void *arg __unused) { uint8_t *keyfile, *data; size_t size, i; #ifdef RANDOM_RWFILE const char **entropy_file; uint8_t *zbuf; int error; #endif /* Get stuff that may have been preloaded by loader(8) */ keyfile = preload_search_by_type("/boot/entropy"); if (keyfile != NULL) { data = preload_fetch_addr(keyfile); size = preload_fetch_size(keyfile); if (data != NULL && size != 0) { for (i = 0; i < size; i += 16) random_harvestq_internal(get_cyclecount(), data + i, 16, 16, RANDOM_CACHED); printf("random: read %zu bytes from preloaded cache\n", size); bzero(data, size); } else printf("random: no preloaded entropy cache available\n"); } #ifdef RANDOM_RWFILE /* Read and attempt to overwrite the entropy cache files. * If the file exists, can be read and then overwritten, * then use it. Ignore it otherwise, but print out what is * going on. */ data = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); zbuf = __DECONST(void *, zero_region); for (entropy_file = entropy_files; *entropy_file; entropy_file++) { error = randomdev_read_file(*entropy_file, data, PAGE_SIZE); if (error == 0) { printf("random: entropy cache '%s' provides %ld bytes\n", *entropy_file, (long)PAGE_SIZE); error = randomdev_write_file(*entropy_file, zbuf, PAGE_SIZE); if (error == 0) { printf("random: entropy cache '%s' contents used and successfully overwritten\n", *entropy_file); for (i = 0; i < PAGE_SIZE; i += 16) random_harvestq_internal(get_cyclecount(), data + i, 16, 16, RANDOM_CACHED); } else printf("random: entropy cache '%s' not overwritten and therefore not used; error = %d\n", *entropy_file, error); } else printf("random: entropy cache '%s' not present or unreadable; error = %d\n", *entropy_file, error); } bzero(data, PAGE_SIZE); free(data, M_ENTROPY); #endif } EVENTHANDLER_DEFINE(mountroot, random_harvestq_cache, NULL, 0); static void random_kthread(void *arg) { STAILQ_HEAD(, harvest) local_queue; struct harvest *event = NULL; int local_count; event_proc_f entropy_processor = arg; STAILQ_INIT(&local_queue); local_count = 0; /* Process until told to stop */ mtx_lock_spin(&harvest_mtx); for (; random_kthread_control >= 0;) { /* * Grab all the entropy events. * Drain entropy source records into a thread-local * queue for processing while not holding the mutex. */ STAILQ_CONCAT(&local_queue, &harvestfifo.head); local_count += harvestfifo.count; harvestfifo.count = 0; /* * Deal with events, if any. * Then transfer the used events back into the empty fifo. */ if (!STAILQ_EMPTY(&local_queue)) { mtx_unlock_spin(&harvest_mtx); STAILQ_FOREACH(event, &local_queue, next) entropy_processor(event); mtx_lock_spin(&harvest_mtx); STAILQ_CONCAT(&emptyfifo.head, &local_queue); emptyfifo.count += local_count; local_count = 0; } KASSERT(local_count == 0, ("random_kthread: local_count %d", local_count)); /* * Do only one round of the hardware sources for now. * Later we'll need to make it rate-adaptive. */ mtx_unlock_spin(&harvest_mtx); live_entropy_sources_feed(1, entropy_processor); mtx_lock_spin(&harvest_mtx); /* * If a queue flush was commanded, it has now happened, * and we can mark this by resetting the command. */ if (random_kthread_control == 1) random_kthread_control = 0; /* Work done, so don't belabour the issue */ msleep_spin_sbt(&random_kthread_control, &harvest_mtx, "-", SBT_1S/10, 0, C_PREL(1)); } mtx_unlock_spin(&harvest_mtx); random_set_wakeup_exit(&random_kthread_control); /* NOTREACHED */ } void random_harvestq_init(event_proc_f cb) { - int error, i; + int i; struct harvest *np; /* Initialise the harvest fifos */ /* Contains the currently unused event structs. */ STAILQ_INIT(&emptyfifo.head); for (i = 0; i < RANDOM_FIFO_MAX; i++) { np = malloc(sizeof(struct harvest), M_ENTROPY, M_WAITOK); STAILQ_INSERT_TAIL(&emptyfifo.head, np, next); } emptyfifo.count = RANDOM_FIFO_MAX; /* Will contain the queued-up events. */ STAILQ_INIT(&harvestfifo.head); harvestfifo.count = 0; mtx_init(&harvest_mtx, "entropy harvest mutex", NULL, MTX_SPIN); + random_cb = cb; +} + +static void +random_harvestq_start_kproc(void *arg __unused) +{ + int error; + + if (random_cb == NULL) + return; + /* Start the hash/reseed thread */ - error = kproc_create(random_kthread, cb, + error = kproc_create(random_kthread, random_cb, &random_kthread_proc, RFHIGHPID, 0, "rand_harvestq"); /* RANDOM_CSPRNG_NAME */ if (error != 0) panic("Cannot create entropy maintenance thread."); } +SYSINIT(random_kthread, SI_SUB_DRIVERS, SI_ORDER_ANY, + random_harvestq_start_kproc, NULL); void random_harvestq_deinit(void) { struct harvest *np; /* Destroy the harvest fifos */ while (!STAILQ_EMPTY(&emptyfifo.head)) { np = STAILQ_FIRST(&emptyfifo.head); STAILQ_REMOVE_HEAD(&emptyfifo.head, next); free(np, M_ENTROPY); } emptyfifo.count = 0; while (!STAILQ_EMPTY(&harvestfifo.head)) { np = STAILQ_FIRST(&harvestfifo.head); STAILQ_REMOVE_HEAD(&harvestfifo.head, next); free(np, M_ENTROPY); } harvestfifo.count = 0; + + /* + * Command the hash/reseed thread to end and wait for it to finish + */ + mtx_lock_spin(&harvest_mtx); + if (random_kthread_proc != NULL) { + random_kthread_control = -1; + msleep_spin((void *)&random_kthread_control, &harvest_mtx, + "term", 0); + } + mtx_unlock_spin(&harvest_mtx); mtx_destroy(&harvest_mtx); } /* * Entropy harvesting routine. * This is supposed to be fast; do not do anything slow in here! * * It is also illegal (and morally reprehensible) to insert any * high-rate data here. "High-rate" is define as a data source * that will usually cause lots of failures of the "Lockless read" * check a few lines below. This includes the "always-on" sources * like the Intel "rdrand" or the VIA Nehamiah "xstore" sources. */ void random_harvestq_internal(u_int64_t somecounter, const void *entropy, u_int count, u_int bits, enum esource origin) { struct harvest *event; KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("random_harvest_internal: origin %d invalid\n", origin)); /* Lockless read to avoid lock operations if fifo is full. */ if (harvestfifo.count >= RANDOM_FIFO_MAX) return; mtx_lock_spin(&harvest_mtx); /* * On't overfill the harvest queue; this could steal all * our memory. */ if (harvestfifo.count < RANDOM_FIFO_MAX) { event = STAILQ_FIRST(&emptyfifo.head); if (event != NULL) { /* Add the harvested data to the fifo */ STAILQ_REMOVE_HEAD(&emptyfifo.head, next); emptyfifo.count--; event->somecounter = somecounter; event->size = count; event->bits = bits; event->source = origin; /* XXXX Come back and make this dynamic! */ count = MIN(count, HARVESTSIZE); memcpy(event->entropy, entropy, count); STAILQ_INSERT_TAIL(&harvestfifo.head, event, next); harvestfifo.count++; } } mtx_unlock_spin(&harvest_mtx); } Index: stable/10/sys/dev/random/randomdev.c =================================================================== --- stable/10/sys/dev/random/randomdev.c (revision 295479) +++ stable/10/sys/dev/random/randomdev.c (revision 295480) @@ -1,233 +1,248 @@ /*- * Copyright (c) 2000-2013 Mark R V Murray * Copyright (c) 2013 Arthur Mesh * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define RANDOM_MINOR 0 static d_read_t random_read; static d_write_t random_write; static d_ioctl_t random_ioctl; static d_poll_t random_poll; static struct cdevsw random_cdevsw = { .d_version = D_VERSION, .d_read = random_read, .d_write = random_write, .d_ioctl = random_ioctl, .d_poll = random_poll, .d_name = "random", }; /* For use with make_dev(9)/destroy_dev(9). */ static struct cdev *random_dev; /* ARGSUSED */ static int random_read(struct cdev *dev __unused, struct uio *uio, int flag) { int c, error = 0; void *random_buf; /* Blocking logic */ if (!random_adaptor->seeded) error = (*random_adaptor->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->read)(random_buf, c); error = uiomove(random_buf, c, uio); } /* Finished reading; let the source know so it can do some * optional housekeeping */ (*random_adaptor->read)(NULL, 0); free(random_buf, M_ENTROPY); } return (error); } /* ARGSUSED */ static int random_write(struct cdev *dev __unused, struct uio *uio, int flag __unused) { /* 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. */ uio->uio_resid = 0; return (0); } /* ARGSUSED */ static int random_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused, int flags __unused, struct thread *td __unused) { int error = 0; switch (cmd) { /* Really handled in upper layer */ case FIOASYNC: case FIONBIO: break; default: error = ENOTTY; } return (error); } /* ARGSUSED */ static int random_poll(struct cdev *dev __unused, int events, struct thread *td) { int revents = 0; if (events & (POLLIN | POLLRDNORM)) { if (random_adaptor->seeded) revents = events & (POLLIN | POLLRDNORM); else revents = (*random_adaptor->poll)(events, td); } return (revents); } static void random_initialize(void *p, struct random_adaptor *s) { static int random_inited = 0; if (random_inited) { printf("random: <%s> already initialized\n", random_adaptor->ident); return; } random_adaptor = s; (s->init)(); printf("random: <%s> initialized\n", s->ident); + /* mark random(4) as initialized, to avoid being called again */ + random_inited = 1; +} + +static void +random_makedev(void *arg __unused) +{ + + if (random_adaptor == NULL) + return; + /* Use an appropriately evil mode for those who are concerned * with daemons */ random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw, RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0666, "random"); make_dev_alias(random_dev, "urandom"); /* compatibility */ - - /* mark random(4) as initialized, to avoid being called again */ - random_inited = 1; } +SYSINIT(random_makedev, SI_SUB_DRIVERS, SI_ORDER_ANY, random_makedev, NULL); /* ARGSUSED */ static int random_modevent(module_t mod __unused, int type, void *data __unused) { static eventhandler_tag attach_tag = NULL; int error = 0; switch (type) { case MOD_LOAD: random_adaptor_choose(&random_adaptor); if (random_adaptor == NULL) { printf("random: No random adaptor attached, " "postponing initialization\n"); attach_tag = EVENTHANDLER_REGISTER(random_adaptor_attach, random_initialize, NULL, EVENTHANDLER_PRI_ANY); } else random_initialize(NULL, random_adaptor); break; case MOD_UNLOAD: if (random_adaptor != NULL) { (*random_adaptor->deinit)(); destroy_dev(random_dev); } /* Unregister the event handler */ if (attach_tag != NULL) EVENTHANDLER_DEREGISTER(random_adaptor_attach, attach_tag); break; case MOD_SHUTDOWN: break; default: error = EOPNOTSUPP; break; } return (error); } -DEV_MODULE(random, random_modevent, NULL); +static moduledata_t random_mod = { + "random", + random_modevent, + NULL +}; + +DECLARE_MODULE(random, random_mod, SI_SUB_RANDOM, SI_ORDER_MIDDLE); MODULE_VERSION(random, 1); Index: stable/10/sys/dev/random/randomdev_soft.c =================================================================== --- stable/10/sys/dev/random/randomdev_soft.c (revision 295479) +++ stable/10/sys/dev/random/randomdev_soft.c (revision 295480) @@ -1,299 +1,293 @@ /*- * Copyright (c) 2000-2013 Mark R V Murray * Copyright (c) 2004 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "opt_random.h" #if !defined(RANDOM_YARROW) && !defined(RANDOM_FORTUNA) #define RANDOM_YARROW #elif defined(RANDOM_YARROW) && defined(RANDOM_FORTUNA) #error "Must define either RANDOM_YARROW or RANDOM_FORTUNA" #endif #if defined(RANDOM_FORTUNA) #error "Fortuna is not yet implemented" #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(RANDOM_YARROW) #include #endif #if defined(RANDOM_FORTUNA) #include #endif static int randomdev_poll(int event, struct thread *td); static int randomdev_block(int flag); static void randomdev_flush_reseed(void); #if defined(RANDOM_YARROW) static struct random_adaptor random_context = { .ident = "Software, Yarrow", .init = randomdev_init, .deinit = randomdev_deinit, .block = randomdev_block, .read = random_yarrow_read, .poll = randomdev_poll, .reseed = randomdev_flush_reseed, .seeded = 0, /* This will be seeded during entropy processing */ .priority = 90, /* High priority, so top of the list. Fortuna may still win. */ }; #define RANDOM_MODULE_NAME yarrow #define RANDOM_CSPRNG_NAME "yarrow" #endif #if defined(RANDOM_FORTUNA) static struct random_adaptor random_context = { .ident = "Software, Fortuna", .init = randomdev_init, .deinit = randomdev_deinit, .block = randomdev_block, .read = random_fortuna_read, .poll = randomdev_poll, .reseed = randomdev_flush_reseed, .seeded = 0, /* This will be excplicitly seeded at startup when secured */ .priority = 100, /* High priority, so top of the list. Beat Yarrow. */ }; #define RANDOM_MODULE_NAME fortuna #define RANDOM_CSPRNG_NAME "fortuna" #endif TUNABLE_INT("kern.random.sys.seeded", &random_context.seeded); /* List for the dynamic sysctls */ static struct sysctl_ctx_list random_clist; /* ARGSUSED */ static int random_check_boolean(SYSCTL_HANDLER_ARGS) { if (oidp->oid_arg1 != NULL && *(u_int *)(oidp->oid_arg1) != 0) *(u_int *)(oidp->oid_arg1) = 1; return (sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req)); } void randomdev_init(void) { struct sysctl_oid *random_sys_o, *random_sys_harvest_o; #if defined(RANDOM_YARROW) random_yarrow_init_alg(&random_clist); #endif #if defined(RANDOM_FORTUNA) random_fortuna_init_alg(&random_clist); #endif random_sys_o = SYSCTL_ADD_NODE(&random_clist, SYSCTL_STATIC_CHILDREN(_kern_random), OID_AUTO, "sys", CTLFLAG_RW, 0, "Entropy Device Parameters"); SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_sys_o), OID_AUTO, "seeded", CTLTYPE_INT | CTLFLAG_RW, &random_context.seeded, 0, random_check_boolean, "I", "Seeded State"); random_sys_harvest_o = SYSCTL_ADD_NODE(&random_clist, SYSCTL_CHILDREN(random_sys_o), OID_AUTO, "harvest", CTLFLAG_RW, 0, "Entropy Sources"); SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_sys_harvest_o), OID_AUTO, "ethernet", CTLTYPE_INT | CTLFLAG_RW, &harvest.ethernet, 1, random_check_boolean, "I", "Harvest NIC entropy"); SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_sys_harvest_o), OID_AUTO, "point_to_point", CTLTYPE_INT | CTLFLAG_RW, &harvest.point_to_point, 1, random_check_boolean, "I", "Harvest serial net entropy"); SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_sys_harvest_o), OID_AUTO, "interrupt", CTLTYPE_INT | CTLFLAG_RW, &harvest.interrupt, 1, random_check_boolean, "I", "Harvest IRQ entropy"); SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_sys_harvest_o), OID_AUTO, "swi", CTLTYPE_INT | CTLFLAG_RW, &harvest.swi, 1, random_check_boolean, "I", "Harvest SWI entropy"); random_harvestq_init(random_process_event); /* Register the randomness harvesting routine */ randomdev_init_harvester(random_harvestq_internal, random_context.read); } void randomdev_deinit(void) { /* Deregister the randomness harvesting routine */ randomdev_deinit_harvester(); - /* - * Command the hash/reseed thread to end and wait for it to finish - */ - random_kthread_control = -1; - tsleep((void *)&random_kthread_control, 0, "term", 0); - #if defined(RANDOM_YARROW) random_yarrow_deinit_alg(); #endif #if defined(RANDOM_FORTUNA) random_fortuna_deinit_alg(); #endif sysctl_ctx_free(&random_clist); } void randomdev_unblock(void) { if (!random_context.seeded) { selwakeuppri(&random_context.rsel, PUSER); wakeup(&random_context); printf("random: unblocking device.\n"); random_context.seeded = 1; } /* 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 randomdev_poll(int events, struct thread *td) { int revents = 0; mtx_lock(&random_reseed_mtx); if (random_context.seeded) revents = events & (POLLIN | POLLRDNORM); else selrecord(td, &random_context.rsel); mtx_unlock(&random_reseed_mtx); return (revents); } static int randomdev_block(int flag) { int error = 0; mtx_lock(&random_reseed_mtx); /* Blocking logic */ while (!random_context.seeded && !error) { if (flag & O_NONBLOCK) error = EWOULDBLOCK; else { printf("random: blocking on read.\n"); error = msleep(&random_context, &random_reseed_mtx, PUSER | PCATCH, "block", 0); } } mtx_unlock(&random_reseed_mtx); return (error); } /* Helper routine to perform explicit reseeds */ static void randomdev_flush_reseed(void) { /* Command a entropy queue flush and wait for it to finish */ random_kthread_control = 1; while (random_kthread_control) pause("-", hz / 10); #if defined(RANDOM_YARROW) /* This ultimately calls randomdev_unblock() */ random_yarrow_reseed(); #endif #if defined(RANDOM_FORTUNA) /* This ultimately calls randomdev_unblock() */ random_fortuna_reseed(); #endif } static int randomdev_modevent(module_t mod __unused, int type, void *unused __unused) { switch (type) { case MOD_LOAD: random_adaptor_register(RANDOM_CSPRNG_NAME, &random_context); /* * For statically built kernels that contain both device * random and options PADLOCK_RNG/RDRAND_RNG/etc.., * this event handler will do nothing, since the random * driver-specific handlers are loaded after these HW * consumers, and hence hasn't yet registered for this event. * * In case where both the random driver and RNG's are built * as seperate modules, random.ko is loaded prior to *_rng.ko's * (by dependency). This event handler is there to delay * creation of /dev/{u,}random and attachment of this *_rng.ko. */ EVENTHANDLER_INVOKE(random_adaptor_attach, &random_context); return (0); } return (EINVAL); } RANDOM_ADAPTOR_MODULE(RANDOM_MODULE_NAME, randomdev_modevent, 1);