diff options
44 files changed, 1025 insertions, 648 deletions
diff --git a/etc/defaults/rc.conf b/etc/defaults/rc.conf index b7a9a0e..d609bd8 100644 --- a/etc/defaults/rc.conf +++ b/etc/defaults/rc.conf @@ -651,6 +651,7 @@ entropy_save_num="8" # Number of entropy cache files to save. harvest_interrupt="YES" # Entropy device harvests interrupt randomness harvest_ethernet="YES" # Entropy device harvests ethernet randomness harvest_p_to_p="YES" # Entropy device harvests point-to-point randomness +harvest_swi="YES" # Entropy device harvests internal SWI randomness dmesg_enable="YES" # Save dmesg(8) to /var/run/dmesg.boot watchdogd_enable="NO" # Start the software watchdog daemon watchdogd_flags="" # Flags to watchdogd (if enabled) diff --git a/etc/rc.d/initrandom b/etc/rc.d/initrandom index 4783873..907668b 100755 --- a/etc/rc.d/initrandom +++ b/etc/rc.d/initrandom @@ -14,26 +14,6 @@ name="initrandom" start_cmd="initrandom_start" stop_cmd=":" -feed_dev_random() -{ - if [ -f "${1}" -a -r "${1}" -a -s "${1}" ]; then - cat "${1}" | dd of=/dev/random bs=8k 2>/dev/null - fi -} - -better_than_nothing() -{ - # XXX temporary until we can improve the entropy - # harvesting rate. - # Entropy below is not great, but better than nothing. - # This unblocks the generator at startup - # Note: commands are ordered to cause the most variance across reboots. - ( kenv; dmesg; df -ib; ps -fauxww; date; sysctl -a ) \ - | dd of=/dev/random bs=8k 2>/dev/null - /sbin/sha256 -q `sysctl -n kern.bootfile` \ - | dd of=/dev/random bs=8k 2>/dev/null -} - initrandom_start() { soft_random_generator=`sysctl kern.random 2>/dev/null` @@ -63,23 +43,15 @@ initrandom_start() else ${SYSCTL} kern.random.sys.harvest.point_to_point=0 >/dev/null fi - fi - # First pass at reseeding /dev/random. - # - case ${entropy_file} in - [Nn][Oo] | '') - ;; - *) - if [ -w /dev/random ]; then - feed_dev_random "${entropy_file}" + if checkyesno harvest_swi; then + ${SYSCTL} kern.random.sys.harvest.swi=1 >/dev/null + echo -n ' swi' + else + ${SYSCTL} kern.random.sys.harvest.swi=0 >/dev/null fi - ;; - esac - - better_than_nothing + fi - echo -n ' kickstart' fi echo '.' diff --git a/share/examples/kld/random_adaptor/random_adaptor_example.c b/share/examples/kld/random_adaptor/random_adaptor_example.c index c0ab10a..da588a8 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 <sys/param.h> #include <sys/kernel.h> +#include <sys/lock.h> #include <sys/module.h> -#include <sys/selinfo.h> +#include <sys/random.h> #include <sys/systm.h> +#include <dev/random/live_entropy_sources.h> #include <dev/random/random_adaptors.h> #include <dev/random/randomdev.h> -#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/share/man/man4/random.4 b/share/man/man4/random.4 index 5e73bc0..a87a2ed7 100644 --- a/share/man/man4/random.4 +++ b/share/man/man4/random.4 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2001 Mark R V Murray. All rights reserved. +.\" Copyright (c) 2001-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 @@ -23,7 +23,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 7, 2013 +.Dd October 12, 2013 .Dt RANDOM 4 .Os .Sh NAME @@ -43,35 +43,48 @@ The device will probe for certain hardware entropy sources, and use these in preference to the fallback, which is a generator implemented in software. -If the kernel environment MIB's -.Va hw.nehemiah_rng_enable -or -.Va hw.ivy_rng_enable -are set to -.Dq Li 0 , -the associated hardware entropy source will be ignored. .Pp -If the device is using -the software generator, -writing data to -.Nm -would perturb the internal state. -This perturbation of the internal state -is the only userland method of introducing -extra entropy into the device. -If the writer has superuser privilege, -then closing the device after writing -will make the software generator reseed itself. -This can be used for extra security, -as it immediately introduces any/all new entropy -into the PRNG. -The hardware generators will generate -sufficient quantities of entropy, -and will therefore ignore user-supplied input. -The software +The software generator will start in an +.Em unseeded +state, and will block reads until +it is (re)seeded. +This may cause trouble at system boot +when keys and the like +are generated from +/dev/random +so steps should be taken to ensure a +reseed as soon as possible. +The +.Xr sysctl 8 +controlling the +.Em seeded +status (see below) may be used +if security is not an issue +or for convenience +during setup or development. +.Pp +This initial seeding +of random number generators +is a bootstrapping problem +that needs very careful attention. +In some cases, +it may be difficult +to find enough randomness +to seed a random number generator +until a system is fully operational, +but the system requires random numbers +to become fully operational. +It is (or more accurately should be) +critically important that the .Nm -device may be controlled with -.Xr sysctl 8 . +device is seeded +before the first time it is used. +In the case where a dummy or "blocking-only" +device is used, +it is the responsibility +of the system architect +to ensure that no blocking reads +hold up critical processes. .Pp To see the current settings of the software .Nm @@ -81,22 +94,20 @@ device, use the command line: .Pp which results in something like: .Bd -literal -offset indent -kern.random.adaptors: yarrow +kern.random.adaptors: yarrow,dummy +kern.random.active_adaptor: yarrow +kern.random.yarrow.gengateinterval: 10 +kern.random.yarrow.bins: 10 +kern.random.yarrow.fastthresh: 96 +kern.random.yarrow.slowthresh: 128 +kern.random.yarrow.slowoverthresh: 2 kern.random.sys.seeded: 1 kern.random.sys.harvest.ethernet: 1 kern.random.sys.harvest.point_to_point: 1 kern.random.sys.harvest.interrupt: 1 -kern.random.sys.harvest.swi: 0 -kern.random.yarrow.gengateinterval: 10 -kern.random.yarrow.bins: 10 -kern.random.yarrow.fastthresh: 192 -kern.random.yarrow.slowthresh: 256 -kern.random.yarrow.slowoverthresh: 2 +kern.random.sys.harvest.swi: 1 .Ed .Pp -(These would not be seen if a -hardware generator is present.) -.Pp Other than .Dl kern.random.adaptors all settings are read/write. @@ -107,9 +118,10 @@ variable indicates whether or not the .Nm device is in an acceptably secure state as a result of reseeding. -If set to 0, the device will block (on read) until the next reseed -(which can be from an explicit write, -or as a result of entropy harvesting). +If set to 0, +the device will block (on read) +until the next reseed +as a result of entropy harvesting. A reseed will set the value to 1 (non-blocking). .Pp The @@ -276,19 +288,6 @@ the generator produce independent sequences. However, the guessability or reproducibility of the sequence is unimportant, unlike the previous cases. .Pp -One final consideration for the seeding of random number generators -is a bootstrapping problem. -In some cases, it may be difficult to find enough randomness to -seed a random number generator until a system is fully operational, -but the system requires random numbers to become fully operational. -There is no substitute for careful thought here, -but the -.Fx -.Nm -device, -which is based on the Yarrow system, -should be of some help in this area. -.Pp .Fx does also provide the traditional .Xr rand 3 @@ -325,17 +324,7 @@ and is an implementation of the .Em Yarrow algorithm by Bruce Schneier, .Em et al . -The only hardware implementations -currently are for the -.Tn VIA C3 Nehemiah -(stepping 3 or greater) -CPU -and the -.Tn Intel -.Dq Bull Mountain -.Em RdRand -instruction and underlying random number generator (RNG). -More will be added in the future. +Significant infrastructure work was done by Arthur Mesh. .Pp The author gratefully acknowledges significant assistance from VIA Technologies, Inc. diff --git a/sys/boot/forth/loader.conf b/sys/boot/forth/loader.conf index 76f40c4..0757b5f 100644 --- a/sys/boot/forth/loader.conf +++ b/sys/boot/forth/loader.conf @@ -39,6 +39,17 @@ bitmap_type="splash_image_data" # and place it on the module_path ############################################################## +### Random number generator configuration ################### +############################################################## + +entropy_cache_load="NO" # Set this to YES to load entropy at boot time +entropy_cache_name="/boot/entropy" # Set this to the name of the file +entropy_cache_type="/boot/entropy" +#kern.random.sys.seeded="0" # Set this to 1 to start /dev/random + # without waiting for a (re)seed. + + +############################################################## ### Loader settings ######################################## ############################################################## diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 975d3f4..d4b205c 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2962,3 +2962,8 @@ options RCTL options BROOKTREE_ALLOC_PAGES=(217*4+1) options MAXFILES=999 +# Random number generator +options RANDOM_YARROW # Yarrow RNG +##options RANDOM_FORTUNA # Fortuna RNG - not yet implemented +options RANDOM_DEBUG # Debugging messages +options RANDOM_RWFILE # Read and write entropy cache diff --git a/sys/conf/files b/sys/conf/files index 9ffad34..f3e298c 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2043,13 +2043,15 @@ 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/random/rwfile.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 9ee6d77..1914c48 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -259,8 +259,8 @@ 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/random/ivy.c optional rdrand_rng +dev/random/nehemiah.c optional 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 b29d8f9..e259659 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -257,8 +257,8 @@ 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/random/ivy.c optional rdrand_rng +dev/random/nehemiah.c optional 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/conf/options b/sys/conf/options index 2c0a1835..ff01144 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -904,3 +904,9 @@ RACCT opt_global.h # Resource Limits RCTL opt_global.h + +# Random number generator(s) +RANDOM_YARROW opt_random.h +RANDOM_FORTUNA opt_random.h +RANDOM_DEBUG opt_random.h +RANDOM_RWFILE opt_random.h diff --git a/sys/dev/glxsb/glxsb.c b/sys/dev/glxsb/glxsb.c index 5204153..646fe3f 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 ae6c5ac..8954242 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 index 15cc7b3..a609da5 100644 --- a/sys/dev/random/pseudo_rng.c +++ b/sys/dev/random/dummy_rng.c @@ -28,93 +28,91 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> -#include <sys/time.h> +#include <sys/fcntl.h> #include <sys/kernel.h> +#include <sys/malloc.h> #include <sys/module.h> +#include <sys/random.h> #include <sys/selinfo.h> #include <sys/systm.h> +#include <sys/time.h> #include <dev/random/random_adaptors.h> #include <dev/random/randomdev.h> -static struct mtx pseudo_random_block_mtx; +static struct mtx dummy_random_mtx; /* Used to fake out unused random calls in random_adaptor */ -void +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 void -pseudo_random_block_init(void) +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); - mtx_init(&pseudo_random_block_mtx, "sleep mtx for random_block", - NULL, MTX_DEF); + return (error); } static void -pseudo_random_block_deinit(void) +dummy_random_init(void) { - mtx_destroy(&pseudo_random_block_mtx); + mtx_init(&dummy_random_mtx, "sleep mtx for dummy_random", + NULL, MTX_DEF); } -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, - .reseed = (random_reseed_func_t *)random_null_func, - .seeded = 1, -}; - -static int -pseudo_random_panic_read(void *buf, int c) +static void +dummy_random_deinit(void) { - panic("Insert a witty panic msg in here."); - - return (0); + mtx_destroy(&dummy_random_mtx); } -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, +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_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); } @@ -122,4 +120,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 473e429..9c10e8d 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/hash.h b/sys/dev/random/hash.h index 62f116d..4e6a4a0 100644 --- a/sys/dev/random/hash.h +++ b/sys/dev/random/hash.h @@ -26,6 +26,9 @@ * $FreeBSD$ */ +#ifndef SYS_DEV_RANDOM_HASH_H_INCLUDED +#define SYS_DEV_RANDOM_HASH_H_INCLUDED + #define KEYSIZE 32 /* (in bytes) == 256 bits */ #define BLOCKSIZE 16 /* (in bytes) == 128 bits */ @@ -43,3 +46,5 @@ void randomdev_hash_iterate(struct randomdev_hash *, void *, size_t); void randomdev_hash_finish(struct randomdev_hash *, void *); void randomdev_encrypt_init(struct randomdev_key *, void *); void randomdev_encrypt(struct randomdev_key *context, void *, void *, unsigned); + +#endif diff --git a/sys/dev/random/ivy.c b/sys/dev/random/ivy.c index 5473312..7784e8b 100644 --- a/sys/dev/random/ivy.c +++ b/sys/dev/random/ivy.c @@ -30,38 +30,35 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> -#include <sys/time.h> #include <sys/kernel.h> #include <sys/lock.h> +#include <sys/malloc.h> #include <sys/module.h> -#include <sys/mutex.h> +#include <sys/random.h> #include <sys/selinfo.h> #include <sys/systm.h> #include <machine/md_var.h> #include <machine/specialreg.h> -#include <dev/random/random_adaptors.h> #include <dev/random/randomdev.h> +#include <dev/random/randomdev_soft.h> +#include <dev/random/random_harvestq.h> +#include <dev/random/live_entropy_sources.h> +#include <dev/random/random_adaptors.h> #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 = { +static 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; @@ -86,34 +83,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 +110,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 0000000..d406ebd --- /dev/null +++ b/sys/dev/random/live_entropy_sources.c @@ -0,0 +1,195 @@ +/*- + * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com> + * 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 <sys/param.h> +__FBSDID("$FreeBSD$"); + +#include <sys/kernel.h> +#include <sys/libkern.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/queue.h> +#include <sys/random.h> +#include <sys/selinfo.h> +#include <sys/sx.h> +#include <sys/sysctl.h> +#include <sys/systm.h> +#include <sys/unistd.h> + +#include <machine/cpu.h> + +#include <dev/random/randomdev.h> +#include <dev/random/randomdev_soft.h> +#include <dev/random/random_adaptors.h> +#include <dev/random/random_harvestq.h> + +#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, + 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 0000000..9a23070 --- /dev/null +++ b/sys/dev/random/live_entropy_sources.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com> + * 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, \ + SI_ORDER_SECOND); \ + MODULE_VERSION(name, ver); \ + MODULE_DEPEND(name, random, 1, 1, 1); + +#endif /* SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED */ diff --git a/sys/dev/random/nehemiah.c b/sys/dev/random/nehemiah.c index 1b4416e..b60689e 100644 --- a/sys/dev/random/nehemiah.c +++ b/sys/dev/random/nehemiah.c @@ -1,6 +1,5 @@ /*- - * Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org> - * 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,133 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> -#include <sys/time.h> +#include <sys/kernel.h> #include <sys/lock.h> -#include <sys/mutex.h> +#include <sys/malloc.h> #include <sys/module.h> +#include <sys/random.h> #include <sys/selinfo.h> #include <sys/systm.h> -#include <sys/kernel.h> +#include <machine/segments.h> #include <machine/pcb.h> #include <machine/md_var.h> #include <machine/specialreg.h> -#include <dev/random/random_adaptors.h> #include <dev/random/randomdev.h> - -#define RANDOM_BLOCK_SIZE 256 -#define CIPHER_BLOCK_SIZE 16 +#include <dev/random/randomdev_soft.h> +#include <dev/random/random_harvestq.h> +#include <dev/random/live_entropy_sources.h> +#include <dev/random/random_adaptors.h> 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, -}; - -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; +static struct random_hardware_source random_nehemiah = { + .ident = "Hardware, VIA Nehemiah Padlock RNG", + .source = RANDOM_PURE_NEHEMIAH, + .read = random_nehemiah_read }; -/* 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. +/* TODO: now that the Davies-Meyer hash is gone and we only use + * the 'xstore' instruction, do we still need to preserve the + * FPU state with fpu_kern_(enter|leave)() ? */ -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); - static struct fpu_kern_ctx *fpu_ctx_save; -static struct mtx random_nehemiah_mtx; - +/* This H/W source never stores more than 8 bytes in one go */ /* 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" + ".byte 0x0f, 0xa7, 0xc0" /* 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; - - 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); + uint64_t tmp; + + 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 43f55f2..e62b2c0 100644 --- a/sys/dev/random/random_adaptors.c +++ b/sys/dev/random/random_adaptors.c @@ -1,7 +1,7 @@ /*- * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com> * Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org> - * 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 <sys/param.h> __FBSDID("$FreeBSD$"); -#include <sys/kernel.h> #include <sys/systm.h> +#include <sys/kernel.h> #include <sys/kthread.h> +#include <sys/libkern.h> #include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/queue.h> #include <sys/random.h> #include <sys/selinfo.h> -#include <sys/sysctl.h> #include <sys/sx.h> -#include <sys/malloc.h> -#include <sys/queue.h> -#include <sys/libkern.h> +#include <sys/sysctl.h> #include <sys/unistd.h> #include <dev/random/randomdev.h> @@ -55,7 +55,7 @@ static struct sysctl_ctx_list random_clist; struct random_adaptor *random_adaptor; -MALLOC_DEFINE(M_RANDOM_ADAPTORS, "random_adaptors", "Random adaptors buffers"); +MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); int random_adaptor_register(const char *name, struct random_adaptor *rsp) @@ -64,8 +64,7 @@ random_adaptor_register(const char *name, struct random_adaptor *rsp) KASSERT(name != NULL && rsp != NULL, ("invalid input to %s", __func__)); - rpp = malloc(sizeof(struct random_adaptors), M_RANDOM_ADAPTORS, - M_WAITOK); + rpp = malloc(sizeof(struct random_adaptors), M_ENTROPY, M_WAITOK); rpp->name = name; rpp->rsp = rsp; @@ -96,30 +95,6 @@ random_adaptor_get(const char *name) } /* - * 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 +109,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"); - - 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); + 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 +157,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 +191,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); } @@ -277,3 +229,15 @@ SYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, random_adaptors_init, NULL); SYSUNINIT(random_adaptors, SI_SUB_DRIVERS, 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); diff --git a/sys/dev/random/random_adaptors.h b/sys/dev/random/random_adaptors.h index fa5f7c8..4765694 100644 --- a/sys/dev/random/random_adaptors.h +++ b/sys/dev/random/random_adaptors.h @@ -26,11 +26,13 @@ * $FreeBSD$ */ -#ifndef __RANDOM_ADAPTORS_H__ -#define __RANDOM_ADAPTORS_H__ +#ifndef SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED +#define SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED #include <sys/eventhandler.h> +MALLOC_DECLARE(M_ENTROPY); + struct random_adaptors { LIST_ENTRY(random_adaptors) entries; /* list of providers */ const char *name; /* name of random adaptor */ @@ -66,4 +68,4 @@ EVENTHANDLER_DECLARE(random_adaptor_attach, random_adaptor_attach_hook); SYSCTL_DECL(_kern_random); #endif /* SYSCTL_DECL */ -#endif /* __RANDOM_ADAPTORS_H__ */ +#endif /* SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED */ diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c index fc87cde..b7b8381 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. * @@ -25,34 +25,42 @@ * (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$ */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_random.h" + #include <sys/param.h> #include <sys/systm.h> +#include <sys/eventhandler.h> #include <sys/kernel.h> #include <sys/kthread.h> +#include <sys/linker.h> #include <sys/lock.h> #include <sys/malloc.h> #include <sys/mutex.h> #include <sys/random.h> +#include <sys/selinfo.h> #include <sys/sysctl.h> #include <sys/unistd.h> -#include <dev/random/randomdev_soft.h> - -#include "random_harvestq.h" +#include <machine/cpu.h> +#include <machine/vmparam.h> -#define RANDOM_FIFO_MAX 256 /* How many events to queue up */ +#include <dev/random/randomdev.h> +#include <dev/random/randomdev_soft.h> +#include <dev/random/random_adaptors.h> +#include <dev/random/random_harvestq.h> +#include <dev/random/live_entropy_sources.h> +#include <dev/random/rwfile.h> -MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers"); +#define RANDOM_FIFO_MAX 1024 /* How many events to queue up */ /* * The harvest mutex protects the consistency of the entropy fifos and - * empty fifo. + * empty fifo and other associated structures. */ struct mtx harvest_mtx; @@ -65,24 +73,88 @@ struct entropyfifo { /* Empty entropy buffers */ static struct entropyfifo emptyfifo; -#define EMPTYBUFFERS 1024 - /* Harvested entropy */ -static struct entropyfifo harvestfifo[ENTROPYSOURCE]; +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; +#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; - enum esource source; - event_proc_f func = arg; + event_proc_f entropy_processor = arg; STAILQ_INIT(&local_queue); local_count = 0; @@ -91,26 +163,23 @@ random_kthread(void *arg) mtx_lock_spin(&harvest_mtx); for (; random_kthread_control >= 0;) { - /* Cycle through all the entropy sources */ - for (source = RANDOM_START; source < ENTROPYSOURCE; source++) { - /* - * Drain entropy source records into a thread-local - * queue for processing while not holding the mutex. - */ - STAILQ_CONCAT(&local_queue, &harvestfifo[source].head); - local_count += harvestfifo[source].count; - harvestfifo[source].count = 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, 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); STAILQ_FOREACH(event, &local_queue, next) - func(event); + entropy_processor(event); mtx_lock_spin(&harvest_mtx); STAILQ_CONCAT(&emptyfifo.head, &local_queue); emptyfifo.count += local_count; @@ -121,15 +190,24 @@ random_kthread(void *arg) 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)); + "-", SBT_1S/10, 0, C_PREL(1)); } mtx_unlock_spin(&harvest_mtx); @@ -143,22 +221,22 @@ random_harvestq_init(event_proc_f cb) { int error, i; struct harvest *np; - enum esource e; /* Initialise the harvest fifos */ + + /* Contains the currently unused event structs. */ 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); } - for (e = RANDOM_START; e < ENTROPYSOURCE; e++) { - STAILQ_INIT(&harvestfifo[e].head); - harvestfifo[e].count = 0; - } + emptyfifo.count = RANDOM_FIFO_MAX; - mtx_init(&harvest_mtx, "entropy harvest mutex", NULL, MTX_SPIN); + /* Will contain the queued-up events. */ + STAILQ_INIT(&harvestfifo.head); + harvestfifo.count = 0; + mtx_init(&harvest_mtx, "entropy harvest mutex", NULL, MTX_SPIN); /* Start the hash/reseed thread */ error = kproc_create(random_kthread, cb, @@ -172,7 +250,6 @@ void random_harvestq_deinit(void) { struct harvest *np; - enum esource e; /* Destroy the harvest fifos */ while (!STAILQ_EMPTY(&emptyfifo.head)) { @@ -180,72 +257,66 @@ random_harvestq_deinit(void) STAILQ_REMOVE_HEAD(&emptyfifo.head, next); free(np, M_ENTROPY); } - for (e = RANDOM_START; e < ENTROPYSOURCE; e++) { - while (!STAILQ_EMPTY(&harvestfifo[e].head)) { - np = STAILQ_FIRST(&harvestfifo[e].head); - STAILQ_REMOVE_HEAD(&harvestfifo[e].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; mtx_destroy(&harvest_mtx); } /* - * Entropy harvesting routine. This is supposed to be fast; do - * not do anything slow in here! + * 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, 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. */ - if (harvestfifo[origin].count >= RANDOM_FIFO_MAX) + if (harvestfifo.count >= RANDOM_FIFO_MAX) return; mtx_lock_spin(&harvest_mtx); /* - * Don't make the harvest queues too big - help to prevent low-grade - * entropy swamping + * On't overfill the harvest queue; this could steal all + * our memory. */ - if (harvestfifo[origin].count < RANDOM_FIFO_MAX) { + 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); - harvestfifo[origin].count++; + emptyfifo.count--; event->somecounter = somecounter; event->size = count; event->bits = bits; - event->frac = frac; event->source = origin; /* XXXX Come back and make this dynamic! */ count = MIN(count, HARVESTSIZE); memcpy(event->entropy, entropy, count); -#if 0 - { - int i; - printf("Harvest:%16jX ", event->somecounter); - for (i = 0; i < event->size; i++) - 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); - } -#endif - - STAILQ_INSERT_TAIL(&harvestfifo[origin].head, + STAILQ_INSERT_TAIL(&harvestfifo.head, event, next); + harvestfifo.count++; } } + mtx_unlock_spin(&harvest_mtx); } - diff --git a/sys/dev/random/random_harvestq.h b/sys/dev/random/random_harvestq.h index 9766c77..a2ac3d1 100644 --- a/sys/dev/random/random_harvestq.h +++ b/sys/dev/random/random_harvestq.h @@ -26,16 +26,17 @@ * $FreeBSD$ */ -#ifndef __RANDOM_HARVEST_H__ -#define __RANDOM_HARVEST_H__ +#ifndef SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED +#define SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED 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; +extern struct mtx harvest_mtx; -#endif /* __RANDOM_HARVEST_H__ */ +#endif /* SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED */ diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c index 0f10e6c..b76cb83 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 <arthurmesh@gmail.com> - * 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 <sys/poll.h> #include <sys/priv.h> #include <sys/proc.h> +#include <sys/random.h> #include <sys/selinfo.h> #include <sys/uio.h> #include <sys/unistd.h> @@ -51,12 +52,14 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <machine/cpu.h> -#include <dev/random/random_adaptors.h> #include <dev/random/randomdev.h> +#include <dev/random/randomdev_soft.h> +#include <dev/random/random_adaptors.h> +#include <dev/random/random_harvestq.h> +#include <dev/random/live_entropy_sources.h> #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 +67,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,29 +74,11 @@ 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; /* 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) { int c, error = 0; @@ -107,15 +91,18 @@ random_read(struct cdev *dev __unused, struct uio *uio, int flag) /* The actual read */ if (!error) { - random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); + 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_TEMP); + free(random_buf, M_ENTROPY); } @@ -126,22 +113,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); - - 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); + /* 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 (error); + return (0); } /* ARGSUSED */ @@ -172,7 +153,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); } @@ -180,6 +161,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); @@ -192,9 +175,11 @@ 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 */ + make_dev_alias(random_dev, "urandom"); /* compatibility */ /* mark random(4) as initialized, to avoid being called again */ random_inited = 1; @@ -204,6 +189,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) { @@ -211,13 +197,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; @@ -227,10 +212,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 75b2c19..5be595f 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 @@ -26,6 +26,9 @@ * $FreeBSD$ */ +#ifndef SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED +#define SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED + /* This header contains only those definitions that are global * and non algorithm-specific for the entropy processor */ @@ -34,7 +37,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,10 +48,14 @@ 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_hardware_source { + const char *ident; + enum esource source; + random_read_func_t *read; +}; + +#endif diff --git a/sys/dev/random/randomdev_soft.c b/sys/dev/random/randomdev_soft.c index 61afb1b..db0b016 100644 --- a/sys/dev/random/randomdev_soft.c +++ b/sys/dev/random/randomdev_soft.c @@ -26,10 +26,15 @@ * */ -#if !defined(YARROW_RNG) && !defined(FORTUNA_RNG) -#define YARROW_RNG -#elif defined(YARROW_RNG) && defined(FORTUNA_RNG) -#error "Must define either YARROW_RNG or FORTUNA_RNG" +#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 <sys/cdefs.h> @@ -53,55 +58,54 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <machine/cpu.h> -#include <dev/random/random_adaptors.h> #include <dev/random/randomdev.h> #include <dev/random/randomdev_soft.h> -#if defined(YARROW_RNG) +#include <dev/random/random_harvestq.h> +#include <dev/random/random_adaptors.h> +#if defined(RANDOM_YARROW) #include <dev/random/yarrow.h> #endif -#if defined(FORTUNA_RNG) +#if defined(RANDOM_FORTUNA) #include <dev/random/fortuna.h> #endif -#include "random_harvestq.h" static int randomdev_poll(int event, struct thread *td); static int randomdev_block(int flag); static void randomdev_flush_reseed(void); -#if defined(YARROW_RNG) +#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, - .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" #endif -#if defined(FORTUNA_RNG) +#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, - .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 +TUNABLE_INT("kern.random.sys.seeded", &random_context.seeded); + /* List for the dynamic sysctls */ static struct sysctl_ctx_list random_clist; @@ -111,7 +115,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 @@ -119,10 +123,10 @@ randomdev_init(void) { struct sysctl_oid *random_sys_o, *random_sys_harvest_o; -#if defined(YARROW_RNG) +#if defined(RANDOM_YARROW) random_yarrow_init_alg(&random_clist); #endif -#if defined(FORTUNA_RNG) +#if defined(RANDOM_FORTUNA) random_fortuna_init_alg(&random_clist); #endif @@ -134,7 +138,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 +159,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); @@ -182,10 +186,10 @@ randomdev_deinit(void) random_kthread_control = -1; tsleep((void *)&random_kthread_control, 0, "term", 0); -#if defined(YARROW_RNG) +#if defined(RANDOM_YARROW) random_yarrow_deinit_alg(); #endif -#if defined(FORTUNA_RNG) +#if defined(RANDOM_FORTUNA) random_fortuna_deinit_alg(); #endif @@ -193,32 +197,15 @@ randomdev_deinit(void) } 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 +214,7 @@ static int randomdev_poll(int events, struct thread *td) { int revents = 0; + mtx_lock(&random_reseed_mtx); if (random_context.seeded) @@ -235,7 +223,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 +238,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 +246,7 @@ randomdev_block(int flag) } mtx_unlock(&random_reseed_mtx); - return error; + return (error); } /* Helper routine to perform explicit reseeds */ @@ -270,16 +258,18 @@ randomdev_flush_reseed(void) while (random_kthread_control) pause("-", hz / 10); -#if defined(YARROW_RNG) +#if defined(RANDOM_YARROW) + /* This ultimately calls randomdev_unblock() */ random_yarrow_reseed(); #endif -#if defined(FORTUNA_RNG) +#if defined(RANDOM_FORTUNA) + /* 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 c92a5a8..cbee779 100644 --- a/sys/dev/random/randomdev_soft.h +++ b/sys/dev/random/randomdev_soft.h @@ -26,6 +26,9 @@ * $FreeBSD$ */ +#ifndef SYS_DEV_RANDOM_RANDOMDEV_SOFT_H_INCLUDED +#define SYS_DEV_RANDOM_RANDOMDEV_SOFT_H_INCLUDED + /* This header contains only those definitions that are global * and harvester-specific for the entropy processor */ @@ -41,26 +44,22 @@ #define HARVESTSIZE 16 /* max size of each harvested entropy unit */ -MALLOC_DECLARE(M_ENTROPY); - /* These are used to queue harvested packets of entropy. The entropy * buffer size is pretty arbitrary. */ 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 +79,8 @@ 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)); \ } + +#endif diff --git a/sys/dev/random/rwfile.c b/sys/dev/random/rwfile.c new file mode 100644 index 0000000..9b38957 --- /dev/null +++ b/sys/dev/random/rwfile.c @@ -0,0 +1,96 @@ +/*- + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_random.h" + +#ifdef RANDOM_RWFILE + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/namei.h> +#include <sys/fcntl.h> +#include <sys/vnode.h> + +#include <dev/random/rwfile.h> + +int +randomdev_read_file(const char *filename, void *buf, size_t length) +{ + struct nameidata nd; + struct thread* td = curthread; + int error; + ssize_t resid; + int flags; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td); + flags = FREAD; + error = vn_open(&nd, &flags, 0, NULL); + if (error == 0) { + NDFREE(&nd, NDF_ONLY_PNBUF); + if (nd.ni_vp->v_type != VREG) + error = ENOEXEC; + else + error = vn_rdwr(UIO_READ, nd.ni_vp, buf, length, 0, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td); + VOP_UNLOCK(nd.ni_vp, 0); + vn_close(nd.ni_vp, FREAD, td->td_ucred, td); + } + + return (error); +} + +int +randomdev_write_file(const char *filename, void *buf, size_t length) +{ + struct nameidata nd; + struct thread* td = curthread; + int error; + ssize_t resid; + int flags; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td); + flags = FWRITE | O_CREAT | O_TRUNC; + error = vn_open(&nd, &flags, 0, NULL); + if (error == 0) { + NDFREE(&nd, NDF_ONLY_PNBUF); + if (nd.ni_vp->v_type != VREG) + error = ENOEXEC; + else + error = vn_rdwr(UIO_WRITE, nd.ni_vp, buf, length, 0, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td); + + VOP_UNLOCK(nd.ni_vp, 0); + vn_close(nd.ni_vp, FREAD, td->td_ucred, td); + } + + return (error); +} + +#endif diff --git a/sys/dev/random/rwfile.h b/sys/dev/random/rwfile.h new file mode 100644 index 0000000..f14fd7b --- /dev/null +++ b/sys/dev/random/rwfile.h @@ -0,0 +1,39 @@ +/*- + * 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_RWFILE_H_INCLUDED +#define SYS_DEV_RANDOM_RWFILE_H_INCLUDED + +#ifdef RANDOM_RWFILE + +int randomdev_read_file(const char *filename, void *buf, size_t); +int randomdev_write_file(const char *filename, void *buf, size_t); + +#endif + +#endif diff --git a/sys/dev/random/yarrow.c b/sys/dev/random/yarrow.c index 21913f9..1cfa373 100644 --- a/sys/dev/random/yarrow.c +++ b/sys/dev/random/yarrow.c @@ -28,6 +28,8 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_random.h" + #include <sys/param.h> #include <sys/kernel.h> #include <sys/lock.h> @@ -67,8 +69,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 */ @@ -99,6 +99,7 @@ clear_counter(void) /* 128-bit C = C + 1 */ /* Nothing to see here, folks, just an ugly mess. */ +/* TODO: Make a Galois counter instead? */ static void increment_counter(void) { @@ -115,16 +116,26 @@ random_process_event(struct harvest *event) struct source *source; enum esource src; - /* Unpack the event into the appropriate source accumulator */ +#if 0 + /* Do this better with DTrace */ + { + int i; + + printf("Harvest:%16jX ", event->somecounter); + for (i = 0; i < event->size; i++) + printf("%02X", event->entropy[i]); + for (; i < 16; i++) + printf(" "); + printf(" %2d %2d %02X\n", event->size, event->bits, event->source); + } +#endif + + /* Accumulate the event into the appropriate pool */ pl = random_state.which; source = &random_state.pool[pl].source[event->source]; - randomdev_hash_iterate(&random_state.pool[pl].hash, event->entropy, - 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 */ + randomdev_hash_iterate(&random_state.pool[pl].hash, event, + sizeof(*event)); + source->bits += event->bits; /* Count the over-threshold sources in each pool */ for (pl = 0; pl < 2; pl++) { @@ -234,6 +245,10 @@ reseed(u_int fastslow) u_int i; enum esource j; +#if 0 + printf("Yarrow: %s reseed\n", fastslow == FAST ? "fast" : "slow"); +#endif + /* The reseed task must not be jumped on */ mtx_lock(&random_reseed_mtx); @@ -286,12 +301,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 +332,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 +378,7 @@ random_yarrow_read(void *buf, int count) } } mtx_unlock(&random_reseed_mtx); - return retval; + return (retval); } static void @@ -384,5 +400,17 @@ generator_gate(void) void random_yarrow_reseed(void) { +#ifdef RANDOM_DEBUG + int i; + + printf("%s(): fast:", __func__); + for (i = RANDOM_START; i < ENTROPYSOURCE; ++i) + printf(" %d", random_state.pool[FAST].source[i].bits); + printf("\n"); + printf("%s(): slow:", __func__); + for (i = RANDOM_START; i < ENTROPYSOURCE; ++i) + printf(" %d", random_state.pool[SLOW].source[i].bits); + printf("\n"); +#endif reseed(SLOW); } diff --git a/sys/dev/random/yarrow.h b/sys/dev/random/yarrow.h index 0bde5b5..f32313e 100644 --- a/sys/dev/random/yarrow.h +++ b/sys/dev/random/yarrow.h @@ -26,7 +26,12 @@ * $FreeBSD$ */ +#ifndef SYS_DEV_RANDOM_YARROW_H_INCLUDED +#define SYS_DEV_RANDOM_YARROW_H_INCLUDED + void random_yarrow_init_alg(struct sysctl_ctx_list *); void random_yarrow_deinit_alg(void); int random_yarrow_read(void *, int); void random_yarrow_reseed(void); + +#endif diff --git a/sys/dev/rndtest/rndtest.c b/sys/dev/rndtest/rndtest.c index 3c42972..e4fd3b0 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 721b9f4..a3590ef 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 21e6d08..4dbd1a7 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 f09973c..b44dd53 100644 --- a/sys/dev/syscons/syscons.c +++ b/sys/dev/syscons/syscons.c @@ -3400,7 +3400,7 @@ next_code: 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 0e1b7cb..6c06b71 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 f4b04c3..e4f1c82 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/kern/subr_bus.c b/sys/kern/subr_bus.c index b3b1852..5c4c329 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -28,6 +28,7 @@ __FBSDID("$FreeBSD$"); #include "opt_bus.h" +#include "opt_random.h" #include <sys/param.h> #include <sys/conf.h> @@ -44,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <sys/condvar.h> #include <sys/queue.h> #include <machine/bus.h> +#include <sys/random.h> #include <sys/rman.h> #include <sys/selinfo.h> #include <sys/signalvar.h> @@ -55,6 +57,7 @@ __FBSDID("$FreeBSD$"); #include <net/vnet.h> +#include <machine/cpu.h> #include <machine/stdarg.h> #include <vm/uma.h> @@ -2766,6 +2769,7 @@ device_probe_and_attach(device_t dev) int device_attach(device_t dev) { + uint64_t attachtime; int error; if (resource_disabled(dev->driver->name, dev->unit)) { @@ -2778,6 +2782,7 @@ device_attach(device_t dev) device_sysctl_init(dev); if (!device_is_quiet(dev)) device_print_child(dev->parent, dev); + attachtime = get_cyclecount(); dev->state = DS_ATTACHING; if ((error = DEVICE_ATTACH(dev)) != 0) { printf("device_attach: %s%d attach returned %d\n", @@ -2790,6 +2795,17 @@ device_attach(device_t dev) dev->state = DS_NOTPRESENT; return (error); } + attachtime = get_cyclecount() - attachtime; + /* + * 4 bits per device is a reasonable value for desktop and server + * hardware with good get_cyclecount() implementations, but may + * need to be adjusted on other platforms. + */ +#ifdef RANDOM_DEBUG + printf("%s(): feeding %d bit(s) of entropy from %s%d\n", + __func__, 4, dev->driver->name, dev->unit); +#endif + random_harvest(&attachtime, sizeof(attachtime), 4, RANDOM_ATTACH); device_sysctl_update(dev); if (dev->busy) dev->state = DS_BUSY; diff --git a/sys/mips/cavium/octeon_rnd.c b/sys/mips/cavium/octeon_rnd.c index 298f06a..27a7078 100644 --- a/sys/mips/cavium/octeon_rnd.c +++ b/sys/mips/cavium/octeon_rnd.c @@ -41,11 +41,6 @@ __FBSDID("$FreeBSD$"); #include <contrib/octeon-sdk/cvmx.h> #include <contrib/octeon-sdk/cvmx-rng.h> -/* - * 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/modules/random/Makefile b/sys/modules/random/Makefile index 60b62af..a0c6077 100644 --- a/sys/modules/random/Makefile +++ b/sys/modules/random/Makefile @@ -12,7 +12,7 @@ SRCS+= ivy.c .endif SRCS+= randomdev_soft.c yarrow.c hash.c SRCS+= rijndael-alg-fst.c rijndael-api-fst.c sha2.c -SRCS+= bus_if.h device_if.h vnode_if.h opt_cpu.h +SRCS+= bus_if.h device_if.h vnode_if.h opt_cpu.h opt_random.h CFLAGS+= -I${.CURDIR}/../.. diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index d5c5521..26e6edb 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -640,7 +640,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, 2, RANDOM_NET_ETHER); ether_demux(ifp, m); CURVNET_RESTORE(); diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c index f36e7ad..262d6d2 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, 2, 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 72fc162..6c18d2a 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, 2, 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 2f86c82..0f26b8b 100644 --- a/sys/sys/random.h +++ b/sys/sys/random.h @@ -39,7 +39,8 @@ int read_random(void *, int); */ enum esource { RANDOM_START = 0, - RANDOM_WRITE = 0, + RANDOM_CACHED = 0, + RANDOM_ATTACH, RANDOM_KEYBOARD, RANDOM_MOUSE, RANDOM_NET_TUN, @@ -47,10 +48,17 @@ enum esource { RANDOM_NET_NG, RANDOM_INTERRUPT, RANDOM_SWI, - RANDOM_PURE, + RANDOM_PURE_OCTEON, + RANDOM_PURE_SAFE, + RANDOM_PURE_GLXSB, + RANDOM_PURE_UBSEC, + RANDOM_PURE_HIFN, + RANDOM_PURE_RDRAND, + RANDOM_PURE_NEHEMIAH, + RANDOM_PURE_RNDTEST, 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 |