diff --git a/share/examples/kld/random_adaptor/random_adaptor_example.c b/share/examples/kld/random_adaptor/random_adaptor_example.c index c0ab10a83fc5..da588a87fe5d 100644 --- a/share/examples/kld/random_adaptor/random_adaptor_example.c +++ b/share/examples/kld/random_adaptor/random_adaptor_example.c @@ -30,32 +30,29 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include -#include +#include #include +#include #include #include -#define RNG_NAME "example" - static int random_example_read(void *, int); struct random_adaptor random_example = { .ident = "Example RNG", - .init = (random_init_func_t *)random_null_func, - .deinit = (random_deinit_func_t *)random_null_func, + .source = RANDOM_PURE_BOGUS, /* Make sure this is in + * sys/random.h and is unique */ .read = random_example_read, - .write = (random_write_func_t *)random_null_func, - .reseed = (random_reseed_func_t *)random_null_func, - .seeded = 1, }; /* * Used under the license provided @ http://xkcd.com/221/ * http://creativecommons.org/licenses/by-nc/2.5/ */ -static u_char +static uint8_t getRandomNumber(void) { return 4; /* chosen by fair dice roll, guaranteed to be random */ @@ -64,14 +61,13 @@ getRandomNumber(void) static int random_example_read(void *buf, int c) { - u_char *b; + uint8_t *b; int count; b = buf; - for (count = 0; count < c; count++) { + for (count = 0; count < c; count++) b[count] = getRandomNumber(); - } printf("returning %d bytes of pure randomness\n", c); return (c); @@ -80,15 +76,26 @@ random_example_read(void *buf, int c) static int random_example_modevent(module_t mod, int type, void *unused) { + int error = 0; switch (type) { case MOD_LOAD: - random_adaptor_register(RNG_NAME, &random_example); - EVENTHANDLER_INVOKE(random_adaptor_attach, &random_example); - return (0); + live_entropy_source_register(&random_example); + break; + + case MOD_UNLOAD: + live_entropy_source_deregister(&random_example); + break; + + case MOD_SHUTDOWN: + break; + + default: + error = EOPNOTSUPP; + break; } - return (EINVAL); + return (error); } -RANDOM_ADAPTOR_MODULE(random_example, random_example_modevent, 1); +LIVE_ENTROPY_SRC_MODULE(live_entropy_source_example, random_example_modevent, 1); diff --git a/sys/conf/files b/sys/conf/files index 7ba7e7c0e172..6e2a358b39a2 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2043,13 +2043,14 @@ rt2860.fw optional rt2860fw | ralfw \ no-obj no-implicit-rule \ clean "rt2860.fw" dev/random/harvest.c standard -dev/random/hash.c optional random -dev/random/pseudo_rng.c standard +dev/random/dummy_rng.c standard dev/random/random_adaptors.c standard -dev/random/random_harvestq.c standard +dev/random/live_entropy_sources.c optional random +dev/random/random_harvestq.c optional random dev/random/randomdev.c optional random dev/random/randomdev_soft.c optional random dev/random/yarrow.c optional random +dev/random/hash.c optional random dev/rc/rc.c optional rc dev/re/if_re.c optional re dev/rndtest/rndtest.c optional rndtest diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index 9ee6d77d4ba4..7ac5d720917d 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -259,8 +259,6 @@ dev/nvme/nvme_sysctl.c optional nvme dev/nvme/nvme_test.c optional nvme dev/nvme/nvme_util.c optional nvme dev/nvram/nvram.c optional nvram isa -dev/random/ivy.c optional random rdrand_rng -dev/random/nehemiah.c optional random padlock_rng dev/qlxge/qls_dbg.c optional qlxge pci dev/qlxge/qls_dump.c optional qlxge pci dev/qlxge/qls_hw.c optional qlxge pci diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index b29d8f9213c1..55017dcaa478 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -257,8 +257,6 @@ dev/nvme/nvme_test.c optional nvme dev/nvme/nvme_util.c optional nvme dev/nvram/nvram.c optional nvram isa dev/pcf/pcf_isa.c optional pcf -dev/random/ivy.c optional random rdrand_rng -dev/random/nehemiah.c optional random padlock_rng dev/sbni/if_sbni.c optional sbni dev/sbni/if_sbni_isa.c optional sbni isa dev/sbni/if_sbni_pci.c optional sbni pci diff --git a/sys/dev/glxsb/glxsb.c b/sys/dev/glxsb/glxsb.c index 52041534da3e..646fe3fe7eae 100644 --- a/sys/dev/glxsb/glxsb.c +++ b/sys/dev/glxsb/glxsb.c @@ -476,7 +476,7 @@ glxsb_rnd(void *v) if (status & SB_RNS_TRNG_VALID) { value = bus_read_4(sc->sc_sr, SB_RANDOM_NUM); /* feed with one uint32 */ - random_harvest(&value, 4, 32/2, 0, RANDOM_PURE); + random_harvest(&value, 4, 32/2, RANDOM_PURE_GLXSB); } callout_reset(&sc->sc_rngco, sc->sc_rnghz, glxsb_rnd, sc); diff --git a/sys/dev/hifn/hifn7751.c b/sys/dev/hifn/hifn7751.c index ae6c5ac6353b..8954242619d1 100644 --- a/sys/dev/hifn/hifn7751.c +++ b/sys/dev/hifn/hifn7751.c @@ -258,7 +258,7 @@ hifn_partname(struct hifn_softc *sc) static void default_harvest(struct rndtest_state *rsp, void *buf, u_int count) { - random_harvest(buf, count, count*NBBY/2, 0, RANDOM_PURE); + random_harvest(buf, count, count*NBBY/2, RANDOM_PURE_HIFN); } static u_int diff --git a/sys/dev/random/pseudo_rng.c b/sys/dev/random/dummy_rng.c similarity index 56% rename from sys/dev/random/pseudo_rng.c rename to sys/dev/random/dummy_rng.c index 13552942f795..eddb7292cf8f 100644 --- a/sys/dev/random/pseudo_rng.c +++ b/sys/dev/random/dummy_rng.c @@ -28,87 +28,90 @@ __FBSDID("$FreeBSD$"); #include -#include +#include #include #include +#include #include #include +#include #include #include -static struct mtx pseudo_random_block_mtx; +static struct mtx dummy_random_mtx; + +/* Used to fake out unused random calls in random_adaptor */ +static void +random_null_func(void) +{ +} static int -pseudo_random_block_read(void *buf __unused, int c __unused) +dummy_random_poll(int events __unused, struct thread *td __unused) { - mtx_lock(&pseudo_random_block_mtx); - - printf("random(4) device is blocking.\n"); - msleep(pseudo_random_block_read, &pseudo_random_block_mtx, 0, - "block", 0); - - mtx_unlock(&pseudo_random_block_mtx); - 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 -pseudo_random_block_init(void) +dummy_random_init(void) { - mtx_init(&pseudo_random_block_mtx, "sleep mtx for random_block", + mtx_init(&dummy_random_mtx, "sleep mtx for dummy_random", NULL, MTX_DEF); } static void -pseudo_random_block_deinit(void) +dummy_random_deinit(void) { - mtx_destroy(&pseudo_random_block_mtx); + mtx_destroy(&dummy_random_mtx); } -struct random_adaptor pseudo_random_block = { - .ident = "pseudo-RNG that always blocks", - .init = pseudo_random_block_init, - .deinit = pseudo_random_block_deinit, - .read = pseudo_random_block_read, - .write = (random_write_func_t *)random_null_func, +struct random_adaptor dummy_random = { + .ident = "Dummy entropy device that always blocks", + .init = dummy_random_init, + .deinit = dummy_random_deinit, + .block = dummy_random_block, + .poll = dummy_random_poll, + .read = (random_read_func_t *)random_null_func, .reseed = (random_reseed_func_t *)random_null_func, - .seeded = 1, + .seeded = 0, /* This device can never be seeded */ }; static int -pseudo_random_panic_read(void *buf, int c) -{ - - panic("Insert a witty panic msg in here."); - - return (0); -} - -struct random_adaptor pseudo_random_panic = { - .ident = "pseudo-RNG that always panics on first read(2)", - .init = (random_init_func_t *)random_null_func, - .deinit = (random_deinit_func_t *)random_null_func, - .read = pseudo_random_panic_read, - .write = (random_write_func_t *)random_null_func, - .reseed = (random_reseed_func_t *)random_null_func, - .seeded = 1, -}; - -static int -pseudo_random_modevent(module_t mod, int type, void *unused) +dummy_random_modevent(module_t mod __unused, int type, void *unused __unused) { switch (type) { case MOD_LOAD: - random_adaptor_register("block", &pseudo_random_block); + random_adaptor_register("dummy", &dummy_random); EVENTHANDLER_INVOKE(random_adaptor_attach, - &pseudo_random_block); - - random_adaptor_register("panic", &pseudo_random_panic); + &dummy_random); return (0); } @@ -116,4 +119,4 @@ pseudo_random_modevent(module_t mod, int type, void *unused) return (EINVAL); } -RANDOM_ADAPTOR_MODULE(pseudo, pseudo_random_modevent, 1); +RANDOM_ADAPTOR_MODULE(dummy, dummy_random_modevent, 1); diff --git a/sys/dev/random/harvest.c b/sys/dev/random/harvest.c index 473e429317a8..9c10e8dca338 100644 --- a/sys/dev/random/harvest.c +++ b/sys/dev/random/harvest.c @@ -48,20 +48,20 @@ __FBSDID("$FreeBSD$"); static int read_random_phony(void *, int); /* Structure holding the desired entropy sources */ -struct harvest_select harvest = { 1, 1, 1, 0 }; +struct harvest_select harvest = { 1, 1, 1, 1 }; static int warned = 0; /* hold the address of the routine which is actually called if * the randomdev is loaded */ -static void (*reap_func)(u_int64_t, const void *, u_int, u_int, u_int, +static void (*reap_func)(u_int64_t, const void *, u_int, u_int, enum esource) = NULL; static int (*read_func)(void *, int) = read_random_phony; /* Initialise the harvester at load time */ void randomdev_init_harvester(void (*reaper)(u_int64_t, const void *, u_int, - u_int, u_int, enum esource), int (*reader)(void *, int)) + u_int, enum esource), int (*reader)(void *, int)) { reap_func = reaper; read_func = reader; @@ -86,12 +86,10 @@ randomdev_deinit_harvester(void) * read which can be quite expensive. */ void -random_harvest(void *entropy, u_int count, u_int bits, u_int frac, - enum esource origin) +random_harvest(void *entropy, u_int count, u_int bits, enum esource origin) { if (reap_func) - (*reap_func)(get_cyclecount(), entropy, count, bits, frac, - origin); + (*reap_func)(get_cyclecount(), entropy, count, bits, origin); } /* Userland-visible version of read_random */ diff --git a/sys/dev/random/ivy.c b/sys/dev/random/ivy.c index 07c87123acc2..c8982129cc4a 100644 --- a/sys/dev/random/ivy.c +++ b/sys/dev/random/ivy.c @@ -30,50 +30,44 @@ __FBSDID("$FreeBSD$"); #include -#include #include #include #include -#include +#include #include #include #include #include +#include #include #include #define RETRY_COUNT 10 -static void random_ivy_init(void); -static void random_ivy_deinit(void); static int random_ivy_read(void *, int); -struct random_adaptor random_ivy = { +struct random_hardware_source random_ivy = { .ident = "Hardware, Intel IvyBridge+ RNG", - .init = random_ivy_init, - .deinit = random_ivy_deinit, - .read = random_ivy_read, - .write = (random_write_func_t *)random_null_func, - .reseed = (random_reseed_func_t *)random_null_func, - .seeded = 1, + .source = RANDOM_PURE_RDRAND, + .read = random_ivy_read }; static inline int -ivy_rng_store(long *tmp) +ivy_rng_store(uint64_t *tmp) { #ifdef __GNUCLIKE_ASM uint32_t count; __asm __volatile( #ifdef __amd64__ - ".byte\t0x48,0x0f,0xc7,0xf0\n\t" /* rdrand %rax */ + "rdrand\t%%rax\n\t" "jnc\t1f\n\t" "movq\t%%rax,%1\n\t" "movl\t$8,%%eax\n" #else /* i386 */ - ".byte\t0x0f,0xc7,0xf0\n\t" /* rdrand %eax */ + "rdrand\t%%eax\n\t" "jnc\t1f\n\t" "movl\t%%eax,%1\n\t" "movl\t$4,%%eax\n" @@ -86,34 +80,26 @@ ivy_rng_store(long *tmp) #endif } -static void -random_ivy_init(void) -{ -} - -void -random_ivy_deinit(void) -{ -} - static int random_ivy_read(void *buf, int c) { - char *b; - long tmp; - int count, res, retry; + uint8_t *b; + int count, ret, retry; + uint64_t tmp; - for (count = c, b = buf; count > 0; count -= res, b += res) { + b = buf; + for (count = c; count > 0; count -= ret) { for (retry = 0; retry < RETRY_COUNT; retry++) { - res = ivy_rng_store(&tmp); - if (res != 0) + ret = ivy_rng_store(&tmp); + if (ret != 0) break; } - if (res == 0) + if (ret == 0) break; - if (res > count) - res = count; - memcpy(b, &tmp, res); + if (ret > count) + ret = count; + memcpy(b, &tmp, ret); + b += ret; } return (c - count); } @@ -121,25 +107,35 @@ random_ivy_read(void *buf, int c) static int rdrand_modevent(module_t mod, int type, void *unused) { + int error = 0; switch (type) { case MOD_LOAD: - if (cpu_feature2 & CPUID2_RDRAND) { - random_adaptor_register("rdrand", &random_ivy); - EVENTHANDLER_INVOKE(random_adaptor_attach, &random_ivy); - return (0); - } else { + if (cpu_feature2 & CPUID2_RDRAND) + live_entropy_source_register(&random_ivy); + else #ifndef KLD_MODULE if (bootverbose) #endif - printf( - "%s: RDRAND feature is not present on this CPU\n", + printf("%s: RDRAND is not present\n", random_ivy.ident); - return (0); - } + break; + + case MOD_UNLOAD: + if (cpu_feature2 & CPUID2_RDRAND) + live_entropy_source_deregister(&random_ivy); + break; + + case MOD_SHUTDOWN: + break; + + default: + error = EOPNOTSUPP; + break; + } - return (EINVAL); + return (error); } -RANDOM_ADAPTOR_MODULE(random_rdrand, rdrand_modevent, 1); +LIVE_ENTROPY_SRC_MODULE(random_rdrand, rdrand_modevent, 1); diff --git a/sys/dev/random/live_entropy_sources.c b/sys/dev/random/live_entropy_sources.c new file mode 100644 index 000000000000..d8eeb67d93a9 --- /dev/null +++ b/sys/dev/random/live_entropy_sources.c @@ -0,0 +1,185 @@ +/*- + * 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 "live_entropy_sources.h" + +LIST_HEAD(les_head, live_entropy_sources); +static struct les_head sources = LIST_HEAD_INITIALIZER(sources); +static struct sx les_lock; /* need a sleepable lock */ + +#define LES_THRESHOLD 10 + +MALLOC_DEFINE(M_LIVE_ENTROPY_SRCS, "live_entropy_sources", + "Live Entropy Sources"); + +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_LIVE_ENTROPY_SRCS, + 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; + + 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); + free(les, M_LIVE_ENTROPY_SRCS); + break; + } + } + sx_xunlock(&les_lock); +} + +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. + */ +void +live_entropy_sources_feed(int rounds) +{ + struct live_entropy_sources *les; + uint8_t buf[HARVESTSIZE]; + 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. + */ + n = les->rsource->read(buf, sizeof(buf)); + /* FIXME: Whine loudly if this didn't work. */ + + /* + * FIXME: Cannot harvest this stuff into the queue; + * the poor thing will choke to death! + */ + random_harvest(buf, n, 0, les->rsource->source); + } + + } + + 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, + live_entropy_sources_init, NULL); +SYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, + live_entropy_sources_deinit, NULL); diff --git a/sys/dev/random/live_entropy_sources.h b/sys/dev/random/live_entropy_sources.h new file mode 100644 index 000000000000..807972f2ddc7 --- /dev/null +++ b/sys/dev/random/live_entropy_sources.h @@ -0,0 +1,58 @@ +/*- + * 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 __LIVE_ENTROPY_SOURCES__ +#define __LIVE_ENTROPY_SOURCES__ + +/* + * 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 */ +}; + +void live_entropy_source_register(struct random_hardware_source *); +void live_entropy_source_deregister(struct random_hardware_source *); +void live_entropy_sources_feed(int); + +#define LIVE_ENTROPY_SRC_MODULE(name, modevent, ver) \ + static moduledata_t name##_mod = { \ + #name, \ + modevent, \ + 0 \ + }; \ + DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, \ + SI_ORDER_SECOND); \ + MODULE_VERSION(name, ver); \ + MODULE_DEPEND(name, random, 1, 1, 1); + +#endif /* __LIVE_ENTROPY_SOURCES__ */ diff --git a/sys/dev/random/nehemiah.c b/sys/dev/random/nehemiah.c index 1b4416eb19c5..8f1ad9eeebc3 100644 --- a/sys/dev/random/nehemiah.c +++ b/sys/dev/random/nehemiah.c @@ -1,6 +1,5 @@ /*- - * Copyright (c) 2013 David E. O'Brien - * Copyright (c) 2004 Mark R V Murray + * Copyright (c) 2013 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,209 +29,126 @@ __FBSDID("$FreeBSD$"); #include -#include +#include #include -#include #include +#include #include #include -#include #include #include #include +#include #include #include -#define RANDOM_BLOCK_SIZE 256 -#define CIPHER_BLOCK_SIZE 16 - static void random_nehemiah_init(void); static void random_nehemiah_deinit(void); static int random_nehemiah_read(void *, int); -struct random_adaptor random_nehemiah = { - .ident = "Hardware, VIA Nehemiah", - .init = random_nehemiah_init, - .deinit = random_nehemiah_deinit, - .read = random_nehemiah_read, - .write = (random_write_func_t *)random_null_func, - .reseed = (random_reseed_func_t *)random_null_func, - .seeded = 1, +struct random_hardware_source random_nehemiah = { + .ident = "Hardware, VIA Nehemiah Padlock RNG", + .source = RANDOM_PURE_NEHEMIAH, + .read = random_nehemiah_read }; -union VIA_ACE_CW { - uint64_t raw; - struct { - u_int round_count : 4; - u_int algorithm_type : 3; - u_int key_generation_type : 1; - u_int intermediate : 1; - u_int decrypt : 1; - u_int key_size : 2; - u_int filler0 : 20; - u_int filler1 : 32; - u_int filler2 : 32; - u_int filler3 : 32; - } field; -}; - -/* The extra 7 is to allow an 8-byte write on the last byte of the - * arrays. The ACE wants the AES data 16-byte/128-bit aligned, and - * it _always_ writes n*64 bits. The RNG does not care about alignment, - * and it always writes n*32 bits or n*64 bits. - */ -static uint8_t key[CIPHER_BLOCK_SIZE+7] __aligned(16); -static uint8_t iv[CIPHER_BLOCK_SIZE+7] __aligned(16); -static uint8_t in[RANDOM_BLOCK_SIZE+7] __aligned(16); -static uint8_t out[RANDOM_BLOCK_SIZE+7] __aligned(16); - -static union VIA_ACE_CW acw __aligned(16); +/* This H/W RNG never stores more than 8 bytes in one go */ static struct fpu_kern_ctx *fpu_ctx_save; -static struct mtx random_nehemiah_mtx; - /* ARGSUSED */ static __inline size_t VIA_RNG_store(void *buf) { -#ifdef __GNUCLIKE_ASM uint32_t retval = 0; uint32_t rate = 0; - /* The .byte line is really VIA C3 "xstore" instruction */ +#ifdef __GNUCLIKE_ASM __asm __volatile( - "movl $0,%%edx \n\t" - ".byte 0x0f, 0xa7, 0xc0" + "movl $0,%%edx\n\t" + "xstore" : "=a" (retval), "+d" (rate), "+D" (buf) : : "memory" ); +#endif if (rate == 0) return (retval&0x1f); -#endif return (0); } -/* ARGSUSED */ -static __inline void -VIA_ACE_cbc(void *in, void *out, size_t count, void *key, union VIA_ACE_CW *cw, void *iv) -{ -#ifdef __GNUCLIKE_ASM - /* The .byte line is really VIA C3 "xcrypt-cbc" instruction */ - __asm __volatile( - "pushf \n\t" - "popf \n\t" - "rep \n\t" - ".byte 0x0f, 0xa7, 0xc8" - : "+a" (iv), "+c" (count), "+D" (out), "+S" (in) - : "b" (key), "d" (cw) - : "cc", "memory" - ); -#endif -} - static void random_nehemiah_init(void) { - acw.raw = 0ULL; - acw.field.round_count = 12; - mtx_init(&random_nehemiah_mtx, "random nehemiah", NULL, MTX_DEF); fpu_ctx_save = fpu_kern_alloc_ctx(FPU_KERN_NORMAL); } -void +static void random_nehemiah_deinit(void) { fpu_kern_free_ctx(fpu_ctx_save); - mtx_destroy(&random_nehemiah_mtx); } static int random_nehemiah_read(void *buf, int c) { - int i, error; + uint8_t *b; size_t count, ret; - uint8_t *p; + uint64_t tmp; - mtx_lock(&random_nehemiah_mtx); - error = fpu_kern_enter(curthread, fpu_ctx_save, FPU_KERN_NORMAL); - if (error != 0) { - mtx_unlock(&random_nehemiah_mtx); - return (0); + if ((fpu_kern_enter(curthread, fpu_ctx_save, FPU_KERN_NORMAL) == 0)) { + b = buf; + for (count = c; count > 0; count -= ret) { + ret = MIN(VIA_RNG_store(&tmp), count); + memcpy(b, &tmp, ret); + b += ret; + } + fpu_kern_leave(curthread, fpu_ctx_save); } + else + c = 0; - /* Get a random AES key */ - count = 0; - p = key; - do { - ret = VIA_RNG_store(p); - p += ret; - count += ret; - } while (count < CIPHER_BLOCK_SIZE); - - /* Get a random AES IV */ - count = 0; - p = iv; - do { - ret = VIA_RNG_store(p); - p += ret; - count += ret; - } while (count < CIPHER_BLOCK_SIZE); - - /* Get a block of random bytes */ - count = 0; - p = in; - do { - ret = VIA_RNG_store(p); - p += ret; - count += ret; - } while (count < RANDOM_BLOCK_SIZE); - - /* This is a Davies-Meyer hash of the most paranoid variety; the - * key, IV and the data are all read directly from the hardware RNG. - * All of these are used precisely once. - */ - VIA_ACE_cbc(in, out, RANDOM_BLOCK_SIZE/CIPHER_BLOCK_SIZE, - key, &acw, iv); - for (i = 0; i < RANDOM_BLOCK_SIZE; i++) - out[i] ^= in[i]; - - c = MIN(RANDOM_BLOCK_SIZE, c); - memcpy(buf, out, (size_t)c); - - fpu_kern_leave(curthread, fpu_ctx_save); - mtx_unlock(&random_nehemiah_mtx); return (c); } static int nehemiah_modevent(module_t mod, int type, void *unused) { + int error = 0; switch (type) { case MOD_LOAD: if (via_feature_rng & VIA_HAS_RNG) { - random_adaptor_register("nehemiah", &random_nehemiah); - EVENTHANDLER_INVOKE(random_adaptor_attach, - &random_nehemiah); - return (0); - } else { + live_entropy_source_register(&random_nehemiah); + random_nehemiah_init(); + } else #ifndef KLD_MODULE if (bootverbose) #endif - printf( - "%s: VIA RNG feature is not present on this CPU\n", + printf("%s: VIA Padlock RNG not present\n", random_nehemiah.ident); - return (0); - } + break; + + case MOD_UNLOAD: + if (via_feature_rng & VIA_HAS_RNG) + random_nehemiah_deinit(); + live_entropy_source_deregister(&random_nehemiah); + break; + + case MOD_SHUTDOWN: + break; + + default: + error = EOPNOTSUPP; + break; + } - return (EINVAL); + return (error); } -RANDOM_ADAPTOR_MODULE(nehemiah, nehemiah_modevent, 1); +LIVE_ENTROPY_SRC_MODULE(nehemiah, nehemiah_modevent, 1); diff --git a/sys/dev/random/random_adaptors.c b/sys/dev/random/random_adaptors.c index 43f55f22fe43..5ea77c27181e 100644 --- a/sys/dev/random/random_adaptors.c +++ b/sys/dev/random/random_adaptors.c @@ -1,7 +1,7 @@ /*- * Copyright (c) 2013 Arthur Mesh * Copyright (c) 2013 David E. O'Brien - * Copyright (c) 2004 Mark R V Murray + * Copyright (c) 2013 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,17 +29,17 @@ #include __FBSDID("$FreeBSD$"); -#include #include +#include #include +#include #include -#include -#include -#include -#include #include #include -#include +#include +#include +#include +#include #include #include @@ -95,30 +95,6 @@ random_adaptor_get(const char *name) return (rsp); } -/* - * In the past, the logic of the random_adaptor selection was inverted, such - * that hardware RNGs would be chosen unless disabled. This routine is here to - * preserve that functionality to avoid folks losing their hardware RNGs by - * upgrading to newer kernel. - */ -static void -random_adaptor_choose_legacy(struct random_adaptor **adaptor) -{ - struct random_adaptor *tmp; - int enable; - - /* Then go looking for hardware */ - enable = 1; - TUNABLE_INT_FETCH("hw.nehemiah_rng_enable", &enable); - if (enable && (tmp = random_adaptor_get("nehemiah"))) - *adaptor = tmp; - - enable = 1; - TUNABLE_INT_FETCH("hw.ivy_rng_enable", &enable); - if (enable && (tmp = random_adaptor_get("rdrand"))) - *adaptor = tmp; -} - /* * Walk a list of registered random(4) adaptors and pick the last non-selected * one. @@ -134,47 +110,29 @@ random_adaptor_choose(struct random_adaptor **adaptor) KASSERT(adaptor != NULL, ("pre-conditions failed")); *adaptor = NULL; - - random_adaptor_choose_legacy(adaptor); - - if (*adaptor != NULL) - return; - if (TUNABLE_STR_FETCH("rngs_want", rngs, sizeof(rngs))) { cp = rngs; - while ((token = strsep(&cp, ",")) != NULL) { + 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); - } + printf("%s random adaptor is not available," + " skipping\n", token); } if (*adaptor == NULL) { /* - * Either no RNGs are prefered via rngs_want tunable, or - * no prefered RNGs are registered. - * Fallback to Yarrow. + * Fallback to the first thing that's on the list of + * available RNGs. */ - *adaptor = random_adaptor_get("yarrow"); + sx_slock(&adaptors_lock); - if (*adaptor == NULL) { - /* - * Yarrow doesn't seem to be available. - * Fallback to the first thing that's on the list of - * available RNGs. - */ - sx_slock(&adaptors_lock); + rpp = LIST_FIRST(&adaptors); + if (rpp != NULL) + *adaptor = rpp->rsp; - rpp = LIST_FIRST(&adaptors); - if (rpp != NULL) - *adaptor = rpp->rsp; - - sx_sunlock(&adaptors_lock); - } + sx_sunlock(&adaptors_lock); if (bootverbose && *adaptor) printf("Falling back to <%s> random adaptor\n", @@ -200,19 +158,16 @@ random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS) sx_slock(&adaptors_lock); - if (LIST_EMPTY(&adaptors)) { + if (LIST_EMPTY(&adaptors)) error = SYSCTL_OUT(req, "", 0); - } else { - + 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; } @@ -237,19 +192,17 @@ random_sysctl_active_adaptor_handler(SYSCTL_HANDLER_ARGS) if (rsp != NULL) { sx_slock(&adaptors_lock); - LIST_FOREACH(rpp, &adaptors, entries) { + LIST_FOREACH(rpp, &adaptors, entries) if (rpp->rsp == rsp) name = rpp->name; - } sx_sunlock(&adaptors_lock); } - if (rsp == NULL || name == NULL) { + if (rsp == NULL || name == NULL) error = SYSCTL_OUT(req, "", 0); - } else { + else error = SYSCTL_OUT(req, name, strlen(name)); - } return (error); } diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c index fc87cde0068d..4f8f34157a19 100644 --- a/sys/dev/random/random_harvestq.c +++ b/sys/dev/random/random_harvestq.c @@ -1,6 +1,6 @@ /*- + * Copyright (c) 2000-2013 Mark R V Murray * Copyright (c) 2013 Arthur Mesh - * Copyright (c) 2000-2009 Mark R V Murray * Copyright (c) 2004 Robert N. M. Watson * All rights reserved. * @@ -46,7 +46,7 @@ __FBSDID("$FreeBSD$"); #include "random_harvestq.h" -#define RANDOM_FIFO_MAX 256 /* How many events to queue up */ +#define RANDOM_FIFO_MAX 1024 /* How many events to queue up */ MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers"); @@ -65,8 +65,6 @@ struct entropyfifo { /* Empty entropy buffers */ static struct entropyfifo emptyfifo; -#define EMPTYBUFFERS 1024 - /* Harvested entropy */ static struct entropyfifo harvestfifo[ENTROPYSOURCE]; @@ -103,9 +101,8 @@ random_kthread(void *arg) } /* - * Deal with events, if any, dropping the mutex as we process - * each event. Then push the events back into the empty - * fifo. + * 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); @@ -120,16 +117,29 @@ random_kthread(void *arg) KASSERT(local_count == 0, ("random_kthread: local_count %d", local_count)); + /* + * Do Hardware/fast RNG source processing here. + */ +#if 0 + while (hardware_source) { + event = hardware_source->read(); + func(event); + hardware_source++; + /* Throttle somehow? */ + } +#endif + /* * 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)); + "-", SBT_1S/10, 0, C_PREL(1)); } mtx_unlock_spin(&harvest_mtx); @@ -148,7 +158,7 @@ random_harvestq_init(event_proc_f cb) /* Initialise the harvest fifos */ STAILQ_INIT(&emptyfifo.head); emptyfifo.count = 0; - for (i = 0; i < EMPTYBUFFERS; i++) { + for (i = 0; i < RANDOM_FIFO_MAX; i++) { np = malloc(sizeof(struct harvest), M_ENTROPY, M_WAITOK); STAILQ_INSERT_TAIL(&emptyfifo.head, np, next); } @@ -197,11 +207,11 @@ random_harvestq_deinit(void) */ void random_harvestq_internal(u_int64_t somecounter, const void *entropy, - u_int count, u_int bits, u_int frac, enum esource origin) + u_int count, u_int bits, enum esource origin) { struct harvest *event; - KASSERT(origin >= RANDOM_START && origin <= RANDOM_PURE, + KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("random_harvest_internal: origin %d invalid\n", origin)); /* Lockless read to avoid lock operations if fifo is full. */ @@ -223,7 +233,6 @@ random_harvestq_internal(u_int64_t somecounter, const void *entropy, event->somecounter = somecounter; event->size = count; event->bits = bits; - event->frac = frac; event->source = origin; /* XXXX Come back and make this dynamic! */ @@ -238,7 +247,7 @@ random_harvestq_internal(u_int64_t somecounter, const void *entropy, printf("%02X", event->entropy[i]); for (; i < 16; i++) printf(" "); - printf(" %2d 0x%2X.%03X %02X\n", event->size, event->bits, event->frac, event->source); + printf(" %2d %2d %02X\n", event->size, event->bits, event->source); } #endif @@ -248,4 +257,3 @@ random_harvestq_internal(u_int64_t somecounter, const void *entropy, } mtx_unlock_spin(&harvest_mtx); } - diff --git a/sys/dev/random/random_harvestq.h b/sys/dev/random/random_harvestq.h index 9766c7728c44..11ccfc46e009 100644 --- a/sys/dev/random/random_harvestq.h +++ b/sys/dev/random/random_harvestq.h @@ -34,7 +34,7 @@ typedef void (*event_proc_f)(struct harvest *event); void random_harvestq_init(event_proc_f); void random_harvestq_deinit(void); void random_harvestq_internal(u_int64_t, const void *, - u_int, u_int, u_int, enum esource); + u_int, u_int, enum esource); extern int random_kthread_control; diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c index 2d24dd56dd50..990324e14d5b 100644 --- a/sys/dev/random/randomdev.c +++ b/sys/dev/random/randomdev.c @@ -1,6 +1,6 @@ /*- + * Copyright (c) 2000-2013 Mark R V Murray * Copyright (c) 2013 Arthur Mesh - * Copyright (c) 2000-2004 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -52,11 +53,11 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #define RANDOM_MINOR 0 -static d_close_t random_close; static d_read_t random_read; static d_write_t random_write; static d_ioctl_t random_ioctl; @@ -64,7 +65,6 @@ static d_poll_t random_poll; static struct cdevsw random_cdevsw = { .d_version = D_VERSION, - .d_close = random_close, .d_read = random_read, .d_write = random_write, .d_ioctl = random_ioctl, @@ -72,34 +72,9 @@ static struct cdevsw random_cdevsw = { .d_name = "random", }; -static eventhandler_tag attach_tag; -static int random_inited; - /* For use with make_dev(9)/destroy_dev(9). */ static struct cdev *random_dev; -struct random_adaptor * -random_get_active_adaptor(void) -{ - - return (random_adaptor); -} - -/* ARGSUSED */ -static int -random_close(struct cdev *dev __unused, int flags, int fmt __unused, - struct thread *td) -{ - if ((flags & FWRITE) && (priv_check(td, PRIV_RANDOM_RESEED) == 0) - && (securelevel_gt(td->td_ucred, 0) == 0)) { - (*random_adaptor->reseed)(); - random_adaptor->seeded = 1; - arc4rand(NULL, 0, 1); /* Reseed arc4random as well. */ - } - - return (0); -} - /* ARGSUSED */ static int random_read(struct cdev *dev __unused, struct uio *uio, int flag) @@ -107,6 +82,10 @@ random_read(struct cdev *dev __unused, struct uio *uio, int flag) int c, error = 0; void *random_buf; + /* XXX: Harvest some entropy from live entropy sources, if available */ + live_entropy_sources_feed(65); /* 65 is meaningless -- + need to decide appropriate value */ + /* Blocking logic */ if (!random_adaptor->seeded) error = (*random_adaptor->block)(flag); @@ -121,6 +100,9 @@ random_read(struct cdev *dev __unused, struct uio *uio, int flag) 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_TEMP); @@ -133,22 +115,16 @@ random_read(struct cdev *dev __unused, struct uio *uio, int flag) static int random_write(struct cdev *dev __unused, struct uio *uio, int flag __unused) { - int c, error = 0; - void *random_buf; - random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); + /* 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; - while (uio->uio_resid > 0) { - c = MIN((int)uio->uio_resid, PAGE_SIZE); - error = uiomove(random_buf, c, uio); - if (error) - break; - (*random_adaptor->write)(random_buf, c); - } - - free(random_buf, M_TEMP); - - return (error); + return (0); } /* ARGSUSED */ @@ -179,7 +155,7 @@ random_poll(struct cdev *dev __unused, int events, struct thread *td) if (random_adaptor->seeded) revents = events & (POLLIN | POLLRDNORM); else - revents = (*random_adaptor->poll) (events,td); + revents = (*random_adaptor->poll)(events, td); } return (revents); } @@ -187,6 +163,8 @@ random_poll(struct cdev *dev __unused, int events, struct thread *td) 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); @@ -199,9 +177,10 @@ random_initialize(void *p, struct random_adaptor *s) printf("random: <%s> initialized\n", s->ident); + /* 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"); /* XXX Deprecated */ /* mark random(4) as initialized, to avoid being called again */ random_inited = 1; @@ -211,6 +190,7 @@ random_initialize(void *p, struct random_adaptor *s) static int random_modevent(module_t mod __unused, int type, void *data __unused) { + static eventhandler_tag attach_tag = NULL; int error = 0; switch (type) { @@ -218,13 +198,12 @@ random_modevent(module_t mod __unused, int type, void *data __unused) random_adaptor_choose(&random_adaptor); if (random_adaptor == NULL) { - printf( - "random: No random adaptor attached, postponing initialization\n"); + printf("random: No random adaptor attached, " + "postponing initialization\n"); attach_tag = EVENTHANDLER_REGISTER(random_adaptor_attach, random_initialize, NULL, EVENTHANDLER_PRI_ANY); - } else { + } else random_initialize(NULL, random_adaptor); - } break; @@ -234,10 +213,9 @@ random_modevent(module_t mod __unused, int type, void *data __unused) destroy_dev(random_dev); } /* Unregister the event handler */ - if (attach_tag != NULL) { + if (attach_tag != NULL) EVENTHANDLER_DEREGISTER(random_adaptor_attach, attach_tag); - } break; diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h index aeb47531ae72..a0e002f89ae7 100644 --- a/sys/dev/random/randomdev.h +++ b/sys/dev/random/randomdev.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000-2004 Mark R V Murray + * Copyright (c) 2000-2013 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,7 +34,6 @@ typedef void random_init_func_t(void); typedef void random_deinit_func_t(void); typedef int random_block_func_t(int); typedef int random_read_func_t(void *, int); -typedef void random_write_func_t(void *, int); typedef int random_poll_func_t(int, struct thread *); typedef void random_reseed_func_t(void); @@ -46,11 +45,12 @@ struct random_adaptor { random_deinit_func_t *deinit; random_block_func_t *block; random_read_func_t *read; - random_write_func_t *write; random_poll_func_t *poll; random_reseed_func_t *reseed; }; -extern void random_ident_hardware(struct random_adaptor **); -extern void random_null_func(void); -struct random_adaptor *random_get_active_adaptor(void); +struct random_hardware_source { + const char *ident; + enum esource source; + random_read_func_t *read; +}; diff --git a/sys/dev/random/randomdev_soft.c b/sys/dev/random/randomdev_soft.c index 61afb1b76a71..80f46df58712 100644 --- a/sys/dev/random/randomdev_soft.c +++ b/sys/dev/random/randomdev_soft.c @@ -76,10 +76,9 @@ static struct random_adaptor random_context = { .deinit = randomdev_deinit, .block = randomdev_block, .read = random_yarrow_read, - .write = randomdev_write, .poll = randomdev_poll, .reseed = randomdev_flush_reseed, - .seeded = 1, + .seeded = 0, /* This will be seeded during entropy processing */ }; #define RANDOM_MODULE_NAME yarrow #define RANDOM_CSPRNG_NAME "yarrow" @@ -92,14 +91,12 @@ static struct random_adaptor random_context = { .deinit = randomdev_deinit, .block = randomdev_block, .read = random_fortuna_read, - .write = randomdev_write, .poll = randomdev_poll, .reseed = randomdev_flush_reseed, - .seeded = 1, + .seeded = 0, /* This will be excplicitly seeded at startup when secured */ }; #define RANDOM_MODULE_NAME fortuna #define RANDOM_CSPRNG_NAME "fortuna" - #endif /* List for the dynamic sysctls */ @@ -111,7 +108,7 @@ 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); + return (sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req)); } void @@ -134,7 +131,7 @@ randomdev_init(void) SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_sys_o), OID_AUTO, "seeded", CTLTYPE_INT | CTLFLAG_RW, - &random_context.seeded, 1, random_check_boolean, "I", + &random_context.seeded, 0, random_check_boolean, "I", "Seeded State"); random_sys_harvest_o = SYSCTL_ADD_NODE(&random_clist, @@ -155,12 +152,12 @@ randomdev_init(void) SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_sys_harvest_o), OID_AUTO, "interrupt", CTLTYPE_INT | CTLFLAG_RW, - &harvest.interrupt, 0, random_check_boolean, "I", + &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, 0, random_check_boolean, "I", + &harvest.swi, 1, random_check_boolean, "I", "Harvest SWI entropy"); random_harvestq_init(random_process_event); @@ -192,33 +189,16 @@ randomdev_deinit(void) sysctl_ctx_free(&random_clist); } -void -randomdev_write(void *buf, int count) -{ - int i; - u_int chunk; - - /* - * Break the input up into HARVESTSIZE chunks. The writer has too - * much control here, so "estimate" the entropy as zero. - */ - for (i = 0; i < count; i += HARVESTSIZE) { - chunk = HARVESTSIZE; - if (i + chunk >= count) - chunk = (u_int)(count - i); - random_harvestq_internal(get_cyclecount(), (char *)buf + i, - chunk, 0, 0, RANDOM_WRITE); - } -} - void randomdev_unblock(void) { if (!random_context.seeded) { - random_context.seeded = 1; 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); } @@ -227,6 +207,7 @@ static int randomdev_poll(int events, struct thread *td) { int revents = 0; + mtx_lock(&random_reseed_mtx); if (random_context.seeded) @@ -235,7 +216,7 @@ randomdev_poll(int events, struct thread *td) selrecord(td, &random_context.rsel); mtx_unlock(&random_reseed_mtx); - return revents; + return (revents); } static int @@ -250,7 +231,7 @@ randomdev_block(int flag) if (flag & O_NONBLOCK) error = EWOULDBLOCK; else { - printf("Entropy device is blocking.\n"); + printf("random: blocking on read.\n"); error = msleep(&random_context, &random_reseed_mtx, PUSER | PCATCH, "block", 0); @@ -258,7 +239,7 @@ randomdev_block(int flag) } mtx_unlock(&random_reseed_mtx); - return error; + return (error); } /* Helper routine to perform explicit reseeds */ @@ -271,15 +252,17 @@ randomdev_flush_reseed(void) pause("-", hz / 10); #if defined(YARROW_RNG) + /* This ultimately calls randomdev_unblock() */ random_yarrow_reseed(); #endif #if defined(FORTUNA_RNG) + /* This ultimately calls randomdev_unblock() */ random_fortuna_reseed(); #endif } static int -randomdev_modevent(module_t mod, int type, void *unused) +randomdev_modevent(module_t mod __unused, int type, void *unused __unused) { switch (type) { diff --git a/sys/dev/random/randomdev_soft.h b/sys/dev/random/randomdev_soft.h index c92a5a8e0725..7ee9053ec3b1 100644 --- a/sys/dev/random/randomdev_soft.h +++ b/sys/dev/random/randomdev_soft.h @@ -49,18 +49,16 @@ MALLOC_DECLARE(M_ENTROPY); struct harvest { uintmax_t somecounter; /* fast counter for clock jitter */ uint8_t entropy[HARVESTSIZE]; /* the harvested entropy */ - u_int size, bits, frac; /* stats about the entropy */ - enum esource source; /* stats about the entropy */ + u_int size, bits; /* stats about the entropy */ + enum esource source; /* origin of the entropy */ STAILQ_ENTRY(harvest) next; /* next item on the list */ }; void randomdev_init(void); void randomdev_deinit(void); -void randomdev_write(void *, int); - void randomdev_init_harvester(void (*)(u_int64_t, const void *, u_int, - u_int, u_int, enum esource), int (*)(void *, int)); + u_int, enum esource), int (*)(void *, int)); void randomdev_deinit_harvester(void); void random_set_wakeup_exit(void *); @@ -80,6 +78,6 @@ random_check_uint_##name(SYSCTL_HANDLER_ARGS) \ else if (*(u_int *)(oidp->oid_arg1) > (max)) \ *(u_int *)(oidp->oid_arg1) = (max); \ } \ - return sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, \ - req); \ + return (sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, \ + req)); \ } diff --git a/sys/dev/random/yarrow.c b/sys/dev/random/yarrow.c index 21913f924f66..635e126da6f4 100644 --- a/sys/dev/random/yarrow.c +++ b/sys/dev/random/yarrow.c @@ -67,8 +67,6 @@ static struct random_state { struct pool { struct source { u_int bits; /* estimated bits of entropy */ - u_int frac; /* fractional bits of entropy - (given as 1024/n) */ } source[ENTROPYSOURCE]; u_int thresh; /* pool reseed threshhold */ struct randomdev_hash hash; /* accumulated entropy */ @@ -122,9 +120,7 @@ random_process_event(struct harvest *event) sizeof(event->entropy)); randomdev_hash_iterate(&random_state.pool[pl].hash, &event->somecounter, sizeof(event->somecounter)); - source->frac += event->frac; - source->bits += event->bits + (source->frac >> 12); /* bits + frac/0x1000 */ - source->frac &= 0xFFF; /* Keep the fractional bits */ + source->bits += event->bits; /* Count the over-threshold sources in each pool */ for (pl = 0; pl < 2; pl++) { @@ -286,12 +282,9 @@ reseed(u_int fastslow) /* 5. Reset entropy estimate accumulators to zero */ - for (i = 0; i <= fastslow; i++) { - for (j = RANDOM_START; j < ENTROPYSOURCE; j++) { + for (i = 0; i <= fastslow; i++) + for (j = RANDOM_START; j < ENTROPYSOURCE; j++) random_state.pool[i].source[j].bits = 0; - random_state.pool[i].source[j].frac = 0; - } - } /* 6. Wipe memory of intermediate values */ @@ -320,6 +313,10 @@ random_yarrow_read(void *buf, int count) int i; int retval; + /* Check for final read request */ + if (buf == NULL && count == 0) + return (0); + /* The reseed task must not be jumped on */ mtx_lock(&random_reseed_mtx); @@ -362,7 +359,7 @@ random_yarrow_read(void *buf, int count) } } mtx_unlock(&random_reseed_mtx); - return retval; + return (retval); } static void diff --git a/sys/dev/rndtest/rndtest.c b/sys/dev/rndtest/rndtest.c index 3c42972c36f7..e4fd3b0b2cbb 100644 --- a/sys/dev/rndtest/rndtest.c +++ b/sys/dev/rndtest/rndtest.c @@ -152,7 +152,7 @@ rndtest_harvest(struct rndtest_state *rsp, void *buf, u_int len) for (len /= sizeof (u_int32_t); len; len--) add_true_randomness(*p++); #else - random_harvest(buf, len, len*NBBY/2, 0, RANDOM_PURE); + random_harvest(buf, len, len*NBBY/2, RANDOM_PURE_RNDTEST); #endif } } diff --git a/sys/dev/safe/safe.c b/sys/dev/safe/safe.c index 721b9f4b2b60..a3590efbeb03 100644 --- a/sys/dev/safe/safe.c +++ b/sys/dev/safe/safe.c @@ -211,7 +211,7 @@ safe_partname(struct safe_softc *sc) static void default_harvest(struct rndtest_state *rsp, void *buf, u_int count) { - random_harvest(buf, count, count*NBBY/2, 0, RANDOM_PURE); + random_harvest(buf, count, count*NBBY/2, RANDOM_PURE_SAFE); } #endif /* SAFE_NO_RNG */ diff --git a/sys/dev/syscons/scmouse.c b/sys/dev/syscons/scmouse.c index 21e6d0830d60..4dbd1a778734 100644 --- a/sys/dev/syscons/scmouse.c +++ b/sys/dev/syscons/scmouse.c @@ -666,7 +666,7 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) mouse = (mouse_info_t*)data; - random_harvest(mouse, sizeof(mouse_info_t), 2, 0, RANDOM_MOUSE); + random_harvest(mouse, sizeof(mouse_info_t), 2, RANDOM_MOUSE); if (cmd == OLD_CONS_MOUSECTL) { static u_char swapb[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; diff --git a/sys/dev/syscons/syscons.c b/sys/dev/syscons/syscons.c index f09973c49a14..b44dd537105b 100644 --- a/sys/dev/syscons/syscons.c +++ b/sys/dev/syscons/syscons.c @@ -3400,7 +3400,7 @@ scgetc(sc_softc_t *sc, u_int flags) sc_touch_scrn_saver(); if (!(flags & SCGETC_CN)) - random_harvest(&c, sizeof(c), 1, 0, RANDOM_KEYBOARD); + random_harvest(&c, sizeof(c), 1, RANDOM_KEYBOARD); if (scp->kbd_mode != K_XLATE) return KEYCHAR(c); diff --git a/sys/dev/ubsec/ubsec.c b/sys/dev/ubsec/ubsec.c index 0e1b7cb5df67..6c06b71820b2 100644 --- a/sys/dev/ubsec/ubsec.c +++ b/sys/dev/ubsec/ubsec.c @@ -259,7 +259,7 @@ ubsec_partname(struct ubsec_softc *sc) static void default_harvest(struct rndtest_state *rsp, void *buf, u_int count) { - random_harvest(buf, count, count*NBBY/2, 0, RANDOM_PURE); + random_harvest(buf, count, count*NBBY/2, RANDOM_PURE_UBSEC); } static int diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c index f4b04c3f71b4..e4f1c823c88d 100644 --- a/sys/kern/kern_intr.c +++ b/sys/kern/kern_intr.c @@ -901,7 +901,7 @@ intr_event_schedule_thread(struct intr_event *ie) p->p_pid, td->td_name); entropy.event = (uintptr_t)ie; entropy.td = ctd; - random_harvest(&entropy, sizeof(entropy), 2, 0, + random_harvest(&entropy, sizeof(entropy), 2, RANDOM_INTERRUPT); } @@ -1055,7 +1055,7 @@ intr_event_schedule_thread(struct intr_event *ie, struct intr_thread *it) p->p_pid, td->td_name); entropy.event = (uintptr_t)ie; entropy.td = ctd; - random_harvest(&entropy, sizeof(entropy), 2, 0, + random_harvest(&entropy, sizeof(entropy), 2, RANDOM_INTERRUPT); } @@ -1146,7 +1146,7 @@ swi_sched(void *cookie, int flags) curproc->p_pid, curthread->td_name); entropy.event = (uintptr_t)ih; entropy.td = curthread; - random_harvest(&entropy, sizeof(entropy), 1, 0, + random_harvest(&entropy, sizeof(entropy), 1, RANDOM_SWI); } diff --git a/sys/mips/cavium/octeon_rnd.c b/sys/mips/cavium/octeon_rnd.c index 298f06aee1dd..27a707810e44 100644 --- a/sys/mips/cavium/octeon_rnd.c +++ b/sys/mips/cavium/octeon_rnd.c @@ -41,11 +41,6 @@ __FBSDID("$FreeBSD$"); #include #include -/* - * XXX - * random_harvest(9) says to call it with no more than 16 bytes, but at least - * safe(4) seems to violate that rule. - */ #define OCTEON_RND_WORDS 2 struct octeon_rnd_softc { @@ -131,7 +126,7 @@ octeon_rnd_harvest(void *arg) for (i = 0; i < OCTEON_RND_WORDS; i++) sc->sc_entropy[i] = cvmx_rng_get_random64(); random_harvest(sc->sc_entropy, sizeof sc->sc_entropy, - (sizeof(sc->sc_entropy)*8)/2, 0, RANDOM_PURE); + (sizeof(sc->sc_entropy)*8)/2, RANDOM_PURE_OCTEON); callout_reset(&sc->sc_callout, hz * 5, octeon_rnd_harvest, sc); } diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 638b3647f6ba..cc5d8b5d6fff 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -639,7 +639,7 @@ ether_input_internal(struct ifnet *ifp, struct mbuf *m) } if (harvest.ethernet) - random_harvest(&(m->m_data), 12, 3, 0, RANDOM_NET_ETHER); + random_harvest(&(m->m_data), 12, 3, RANDOM_NET_ETHER); ether_demux(ifp, m); CURVNET_RESTORE(); diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c index f36e7ada3d2d..6a73d7cfbcd8 100644 --- a/sys/net/if_tun.c +++ b/sys/net/if_tun.c @@ -918,7 +918,7 @@ tunwrite(struct cdev *dev, struct uio *uio, int flag) return (EAFNOSUPPORT); } if (harvest.point_to_point) - random_harvest(&(m->m_data), 12, 3, 0, RANDOM_NET_TUN); + random_harvest(&(m->m_data), 12, 3, RANDOM_NET_TUN); ifp->if_ibytes += m->m_pkthdr.len; ifp->if_ipackets++; CURVNET_SET(ifp->if_vnet); diff --git a/sys/netgraph/ng_iface.c b/sys/netgraph/ng_iface.c index 72fc16201df9..12ee3a5cd4a2 100644 --- a/sys/netgraph/ng_iface.c +++ b/sys/netgraph/ng_iface.c @@ -775,7 +775,7 @@ ng_iface_rcvdata(hook_p hook, item_p item) return (EAFNOSUPPORT); } if (harvest.point_to_point) - random_harvest(&(m->m_data), 12, 3, 0, RANDOM_NET_NG); + random_harvest(&(m->m_data), 12, 3, RANDOM_NET_NG); M_SETFIB(m, ifp->if_fib); netisr_dispatch(isr, m); return (0); diff --git a/sys/sys/random.h b/sys/sys/random.h index 2f86c82e854a..efaa58793a8c 100644 --- a/sys/sys/random.h +++ b/sys/sys/random.h @@ -47,10 +47,17 @@ enum esource { RANDOM_NET_NG, RANDOM_INTERRUPT, RANDOM_SWI, + RANDOM_PURE_OCTEON, + RANDOM_PURE_SAFE, + RANDOM_PURE_GLXSB, + RANDOM_PURE_UBSEC, + RANDOM_PURE_HIFN, + RANDOM_PURE_RDRAND, + RANDOM_PURE_NEHEMIAH, RANDOM_PURE, ENTROPYSOURCE }; -void random_harvest(void *, u_int, u_int, u_int, enum esource); +void random_harvest(void *, u_int, u_int, enum esource); /* Allow the sysadmin to select the broad category of * entropy types to harvest