Author: markm Date: Mon Aug 17 07:36:12 2015 New Revision: 286839 URL: https://svnweb.freebsd.org/changeset/base/286839
Log: Add DEV_RANDOM pseudo-option and use it to "include out" random(4) if desired. Retire randomdev_none.c and introduce random_infra.c for resident infrastructure. Completely stub out random(4) calls in the "without DEV_RANDOM" case. Add RANDOM_LOADABLE option to allow loadable Yarrow/Fortuna/LocallyWritten algorithm. Add a skeleton "other" algorithm framework for folks to add their own processing code. NIST, anyone? Retire the RANDOM_DUMMY option. Build modules for Yarrow, Fortuna and "other". Use atomics for the live entropy rate-tracking. Convert ints to bools for the 'seeded' logic. Move _write() function from the algorithm-specific areas to randomdev.c Get rid of reseed() function - it is unused. Tidy up the opt_*.h includes. Update documentation for random(4) modules. Fix test program (reviewers, please leave this). Differential Revision: https://reviews.freebsd.org/D3354 Reviewed by: wblock,delphij,jmg,bjk Approved by: so (/dev/random blanket) Added: head/sys/dev/random/other_algorithm.c (contents, props changed) head/sys/dev/random/other_algorithm.h (contents, props changed) head/sys/dev/random/random_infra.c (contents, props changed) head/sys/modules/random_fortuna/ head/sys/modules/random_fortuna/Makefile (contents, props changed) head/sys/modules/random_other/ head/sys/modules/random_other/Makefile (contents, props changed) head/sys/modules/random_yarrow/ head/sys/modules/random_yarrow/Makefile (contents, props changed) Deleted: head/sys/dev/random/randomdev_none.c Modified: head/UPDATING head/share/man/man4/random.4 head/sys/conf/NOTES head/sys/conf/files head/sys/conf/options head/sys/dev/random/fortuna.c head/sys/dev/random/random_harvestq.c head/sys/dev/random/random_harvestq.h head/sys/dev/random/randomdev.c head/sys/dev/random/randomdev.h head/sys/dev/random/unit_test.c head/sys/dev/random/yarrow.c head/sys/modules/Makefile head/sys/sys/random.h Modified: head/UPDATING ============================================================================== --- head/UPDATING Mon Aug 17 05:59:36 2015 (r286838) +++ head/UPDATING Mon Aug 17 07:36:12 2015 (r286839) @@ -31,6 +31,21 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 11 disable the most expensive debugging functionality run "ln -s 'abort:false,junk:false' /etc/malloc.conf".) +20150817: + Kernel-loadable modules for the random(4) device are back. To use + them, the kernel must have + + device random + options RANDOM_LOADABLE + + kldload(8) can then be used to load random_fortuna.ko + or random_yarrow.ko. Please note that due to the indirect + function calls that the loadable modules need to provide, + the build-in variants will be slightly more efficient. + + The random(4) kernel option RANDOM_DUMMY has been retired due to + unpopularity. It was not all that useful anyway. + 20150813: The WITHOUT_ELFTOOLCHAIN_TOOLS src.conf(5) knob has been retired. Control over building the ELF Tool Chain tools is now provided by Modified: head/share/man/man4/random.4 ============================================================================== --- head/share/man/man4/random.4 Mon Aug 17 05:59:36 2015 (r286838) +++ head/share/man/man4/random.4 Mon Aug 17 07:36:12 2015 (r286839) @@ -23,7 +23,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 30, 2015 +.Dd August 17, 2015 .Dt RANDOM 4 .Os .Sh NAME @@ -31,6 +31,7 @@ .Nd the entropy device .Sh SYNOPSIS .Cd "device random" +.Cd "options RANDOM_LOADABLE" .Sh DESCRIPTION The .Nm @@ -133,15 +134,49 @@ The .Va kern.random.harvest.mask_bin and .Va kern.random.harvest.mask_symbolic -sysctl -can be used confirm -that your choices are correct. +sysctls +can be used to confirm +that the choices are correct. Note that disabled items in the latter item are listed in square brackets. See .Xr random_harvest 9 for more on the harvesting of entropy. +.Pp +When +.Cd "options RANDOM_LOADABLE" +is used, +the +.Pa /dev/random +device is not created +until an "algorithm module" +is loaded. +Two of these modules +are built by default, +.Em random_fortuna +and +.Em random_yarrow . +The +.Em random_yarrow +module is deprecated, +and will be removed in +.Fx 12. +Use of the Yarrow algorithm +is not encouraged, +but while still present +in the kernel source, +it can be selected with the +.Cd "options RANDOM_YARROW" +kernel option. +Note that these loadable modules +are slightly less efficient +than their compiled-in equivalents. +This is because some functions +must be locked against +load and unload events, +and also must be indirect calls +to allow for removal. .Sh RANDOMNESS The use of randomness in the field of computing is a rather subtle issue because randomness means @@ -294,7 +329,7 @@ It replaces the previous implementation, introduced in .Fx 5.0 . -The older -.Em Yarrow -algorithm remains available -as a compile-time fallback. +The Yarrow algorithm +is no longer supported +by its authors, +and is therefore deprecated. Modified: head/sys/conf/NOTES ============================================================================== --- head/sys/conf/NOTES Mon Aug 17 05:59:36 2015 (r286838) +++ head/sys/conf/NOTES Mon Aug 17 07:36:12 2015 (r286839) @@ -2981,9 +2981,10 @@ options MAXFILES=999 # Random number generator # Only ONE of the below two may be used; they are mutually exclusive. -# If neither is present, then the Fortuna algorithm is used. -options RANDOM_YARROW # Yarrow CSPRNG (old default) -#options RANDOM_DUMMY # Dummy CSPRNG that always blocks +# If neither is present, then the Fortuna algorithm is selected. +#options RANDOM_YARROW # Yarrow CSPRNG (old default) +#options RANDOM_LOADABLE # Allow the algorithm to be loaded as + # a module. # For developers. options RANDOM_DEBUG # Extra debugging messages Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Mon Aug 17 05:59:36 2015 (r286838) +++ head/sys/conf/files Mon Aug 17 07:36:12 2015 (r286839) @@ -550,14 +550,14 @@ crypto/des/des_ecb.c optional crypto | crypto/des/des_setkey.c optional crypto | ipsec | netsmb crypto/rc4/rc4.c optional netgraph_mppc_encryption | kgssapi crypto/rijndael/rijndael-alg-fst.c optional crypto | geom_bde | \ - ipsec | random random_yarrow | random !random_yarrow !random_dummy | wlan_ccmp -crypto/rijndael/rijndael-api-fst.c optional geom_bde | random random_yarrow | random !random_yarrow !random_dummy + ipsec | random !random_loadable | wlan_ccmp +crypto/rijndael/rijndael-api-fst.c optional geom_bde | random !random_loadable crypto/rijndael/rijndael-api.c optional crypto | ipsec | wlan_ccmp crypto/sha1.c optional carp | crypto | ipsec | \ netgraph_mppc_encryption | sctp -crypto/sha2/sha2.c optional crypto | geom_bde | ipsec | random random_yarrow | random !random_yarrow !random_dummy | \ +crypto/sha2/sha2.c optional crypto | geom_bde | ipsec | random !random_loadable | \ sctp | zfs -crypto/sha2/sha256c.c optional crypto | geom_bde | ipsec | random random_yarrow | random !random_yarrow !random_dummy | \ +crypto/sha2/sha256c.c optional crypto | geom_bde | ipsec | random !random_loadable | \ sctp | zfs crypto/siphash/siphash.c optional inet | inet6 crypto/siphash/siphash_test.c optional inet | inet6 @@ -2314,12 +2314,14 @@ rt2860.fw optional rt2860fw | ralfw \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rt2860.fw" -dev/random/randomdev_none.c optional !random -dev/random/randomdev.c optional random -dev/random/random_harvestq.c optional random random_yarrow | random !random_dummy +dev/random/random_infra.c optional random +dev/random/random_harvestq.c optional random +dev/random/randomdev.c optional random random_yarrow | \ + random !random_yarrow !random_loadable dev/random/yarrow.c optional random random_yarrow -dev/random/fortuna.c optional random !random_yarrow !random_dummy -dev/random/hash.c optional random random_yarrow | random !random_dummy +dev/random/fortuna.c optional random !random_yarrow !random_loadable +dev/random/hash.c optional random random_yarrow | \ + random !random_yarrow !random_loadable dev/rc/rc.c optional rc dev/re/if_re.c optional re dev/rl/if_rl.c optional rl pci Modified: head/sys/conf/options ============================================================================== --- head/sys/conf/options Mon Aug 17 05:59:36 2015 (r286838) +++ head/sys/conf/options Mon Aug 17 07:36:12 2015 (r286839) @@ -711,6 +711,7 @@ DEV_PCI opt_pci.h DEV_PF opt_pf.h DEV_PFLOG opt_pf.h DEV_PFSYNC opt_pf.h +DEV_RANDOM opt_global.h DEV_SPLASH opt_splash.h DEV_VLAN opt_vlan.h @@ -946,13 +947,14 @@ RCTL opt_global.h # The DEBUG option is in global.h as the random harvesting # puts probes all over the place, and it makes little sense # to pollute these headers with an extra include. -# the DUMMY option is in global.h because it is used to -# turn off harvesting all over the kernel. -RANDOM_DEBUG opt_global.h +RANDOM_DEBUG opt_random.h # Which CSPRNG hashes we get. -# These are mutually exclusive. With neither, Fortuna is selected. -RANDOM_DUMMY opt_global.h +# If Yarrow is not chosen, Fortuna is selected. RANDOM_YARROW opt_random.h +# With this, no entropy processor is loaded, but the entropy +# harvesting infrastructure is present. This means an entropy +# processor may be loaded as a module. +RANDOM_LOADABLE opt_random.h # Intel em(4) driver EM_MULTIQUEUE opt_em.h Modified: head/sys/dev/random/fortuna.c ============================================================================== --- head/sys/dev/random/fortuna.c Mon Aug 17 05:59:36 2015 (r286838) +++ head/sys/dev/random/fortuna.c Mon Aug 17 07:36:12 2015 (r286839) @@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$"); #include <dev/random/fortuna.h> #else /* !_KERNEL */ #include <inttypes.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -124,9 +125,7 @@ static uint8_t zero_region[RANDOM_ZERO_B static void random_fortuna_pre_read(void); static void random_fortuna_read(uint8_t *, u_int); -static void random_fortuna_write(uint8_t *, u_int); -static void random_fortuna_reseed(void); -static int random_fortuna_seeded(void); +static bool random_fortuna_seeded(void); static void random_fortuna_process_event(struct harvest_event *); static void random_fortuna_init_alg(void *); static void random_fortuna_deinit_alg(void *); @@ -139,8 +138,6 @@ struct random_algorithm random_alg_conte .ra_deinit_alg = random_fortuna_deinit_alg, .ra_pre_read = random_fortuna_pre_read, .ra_read = random_fortuna_read, - .ra_write = random_fortuna_write, - .ra_reseed = random_fortuna_reseed, .ra_seeded = random_fortuna_seeded, .ra_event_processor = random_fortuna_process_event, .ra_poolcount = RANDOM_FORTUNA_NPOOLS, @@ -420,43 +417,7 @@ random_fortuna_read(uint8_t *buf, u_int RANDOM_RESEED_UNLOCK(); } -/* Internal function to hand external entropy to the PRNG. */ -void -random_fortuna_write(uint8_t *buf, u_int count) -{ - static u_int destination = 0; - struct harvest_event event; - struct randomdev_hash hash; - uint32_t entropy_data[RANDOM_KEYSIZE_WORDS], timestamp; - int i; - - /* Extra timing here is helpful to scrape scheduler timing entropy */ - randomdev_hash_init(&hash); - timestamp = (uint32_t)get_cyclecount(); - randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); - randomdev_hash_iterate(&hash, buf, count); - timestamp = (uint32_t)get_cyclecount(); - randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp)); - randomdev_hash_finish(&hash, entropy_data); - explicit_bzero(&hash, sizeof(hash)); - for (i = 0; i < RANDOM_KEYSIZE_WORDS; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) { - event.he_somecounter = (uint32_t)get_cyclecount(); - event.he_size = sizeof(event.he_entropy); - event.he_bits = event.he_size/8; - event.he_source = RANDOM_CACHED; - event.he_destination = destination++; /* Harmless cheating */ - memcpy(event.he_entropy, entropy_data + i, sizeof(event.he_entropy)); - random_fortuna_process_event(&event); - } - explicit_bzero(entropy_data, sizeof(entropy_data)); -} - -void -random_fortuna_reseed(void) -{ -} - -int +bool random_fortuna_seeded(void) { Added: head/sys/dev/random/other_algorithm.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/random/other_algorithm.c Mon Aug 17 07:36:12 2015 (r286839) @@ -0,0 +1,209 @@ +/*- + * Copyright (c) 2015 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. + * + */ + +/*- + * This is a skeleton for folks who wish to build a loadable module + * containing an alternative entropy-processing algorithm for random(4). + * + * The functions below should be completed with the appropriate code, + * and the nearby yarrow.c and fortuna.c may be consulted for examples + * of working code. + * + * The author is willing to provide reasonable help to those wishing to + * write such a module for themselves. Please use the markm@ FreeBSD + * email address, and ensure that you are developing this on a suitably + * supported branch (This is currently 11-CURRENT, and will be no + * older than 11-STABLE in the future). + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mutex.h> +#include <sys/random.h> +#include <sys/sysctl.h> +#include <sys/systm.h> + +#include <machine/cpu.h> + +#include <crypto/rijndael/rijndael-api-fst.h> +#include <crypto/sha2/sha2.h> + +#include <dev/random/hash.h> +#include <dev/random/randomdev.h> +#include <dev/random/random_harvestq.h> +#include <dev/random/uint128.h> +#include <dev/random/other_algorithm.h> + +static void random_other_pre_read(void); +static void random_other_read(uint8_t *, u_int); +static bool random_other_seeded(void); +static void random_other_process_event(struct harvest_event *); +static void random_other_init_alg(void *); +static void random_other_deinit_alg(void *); + +/* + * RANDOM_OTHER_NPOOLS is used when reading hardware random + * number sources to ensure that each pool gets one read sample + * per loop iteration. Yarrow has 2 such pools (FAST and SLOW), + * and fortuna has 32 (0-31). The RNG used prior to Yarrow and + * ported from Linux had just 1 pool. + */ +#define RANDOM_OTHER_NPOOLS 1 + +struct random_algorithm random_alg_context = { + .ra_ident = "other", + .ra_init_alg = random_other_init_alg, + .ra_deinit_alg = random_other_deinit_alg, + .ra_pre_read = random_other_pre_read, + .ra_read = random_other_read, + .ra_seeded = random_other_seeded, + .ra_event_processor = random_other_process_event, + .ra_poolcount = RANDOM_OTHER_NPOOLS, +}; + +/* Use a mutex to protect your reseed variables? */ +static mtx_t other_mtx; + +/* + * void random_other_init_alg(void *unused __unused) + * + * Do algorithm-specific initialisation here. + */ +void +random_other_init_alg(void *unused __unused) +{ + + RANDOM_RESEED_INIT_LOCK(); + /* + * Do set-up work here! + */ +} + +/* + * void random_other_deinit_alg(void *unused __unused) + * + * Do algorithm-specific deinitialisation here. + */ +static void +random_other_deinit_alg(void *unused __unused) +{ + + /* + * Do tear-down work here! + */ + RANDOM_RESEED_DEINIT_LOCK(); +} + +/* + * void random_other_pre_read(void) + * + * Do any pre-read preparation you need to. This will be called + * before >=1 calls to random_other_read() corresponding to one + * read(2). + * + * This routine will be called periodically while the generator is + * still blocked and a read is being attempted, giving you an + * opportunity to unblock. + */ +static void +random_other_pre_read(void) +{ + + RANDOM_RESEED_LOCK(); + /* + * Do pre-read housekeeping work here! + * You may use this as a chance to unblock the generator. + */ + RANDOM_RESEED_UNLOCK(); +} + +/* + * void random_other_read(uint8_t *buf, u_int count) + * + * Generate <count> bytes of output into <*buf>. + * You may use the fact that <count> will be a multiple of + * RANDOM_BLOCKSIZE for optimization purposes. + * + * This function will always be called with your generator + * unblocked and ready. If you are not ready to generate + * output here, then feel free to KASSERT() or panic(). + */ +static void +random_other_read(uint8_t *buf, u_int count) +{ + + RANDOM_RESEED_LOCK(); + /* + * Do random-number generation work here! + */ + RANDOM_RESEED_UNLOCK(); +} + +/* + * bool random_other_seeded(void) + * + * Return true if your generator is ready to generate + * output, and false otherwise. + */ +static bool +random_other_seeded(void) +{ + bool seeded = false; + + /* + * Find out if your generator is seeded here! + */ + return (seeded); +} + +/* + * void random_other_process_event(struct harvest_event *event) + * + * Process one stochastic event <*event> into your entropy + * processor. + * + * The structure of the event may change, so it is easier to + * just grab the whole thing into your accumulation system. + * You may pick-and-choose bits, but please don't complain + * when/if these change. + */ +static void +random_other_process_event(struct harvest_event *event) +{ + + RANDOM_RESEED_LOCK(); + /* + * Do entropy accumulation work here! + * You may use this as a chance to unblock the generator. + */ + RANDOM_RESEED_UNLOCK(); +} Added: head/sys/dev/random/other_algorithm.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/random/other_algorithm.h Mon Aug 17 07:36:12 2015 (r286839) @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2015 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$ + */ + +/*- + * This is a skeleton for folks who wish to build a loadable module + * containing an alternative entropy-processing algorithm for random(4). + * + * The functions below should be completed with the appropriate code, + * and the nearby yarrow.c and fortuna.c may be consulted for examples + * of working code. + * + * The author is willing to provide reasonable help to those wishing to + * write such a module for themselves. Please use the markm@ FreeBSD + * email address, and ensure that you are developing this on a suitably + * supported branch (This is currently 11-CURRENT, and will be no + * older than 11-STABLE in the future). + */ + +#ifndef SYS_DEV_RANDOM_OTHER_H_INCLUDED +#define SYS_DEV_RANDOM_OTHER_H_INCLUDED + +#ifdef _KERNEL +typedef struct mtx mtx_t; +#define RANDOM_RESEED_INIT_LOCK(x) mtx_init(&other_mtx, "reseed mutex", NULL, MTX_DEF) +#define RANDOM_RESEED_DEINIT_LOCK(x) mtx_destroy(&other_mtx) +#define RANDOM_RESEED_LOCK(x) mtx_lock(&other_mtx) +#define RANDOM_RESEED_UNLOCK(x) mtx_unlock(&other_mtx) +#define RANDOM_RESEED_ASSERT_LOCK_OWNED(x) mtx_assert(&other_mtx, MA_OWNED) +#else +#define RANDOM_RESEED_INIT_LOCK(x) mtx_init(&other_mtx, mtx_plain) +#define RANDOM_RESEED_DEINIT_LOCK(x) mtx_destroy(&other_mtx) +#define RANDOM_RESEED_LOCK(x) mtx_lock(&other_mtx) +#define RANDOM_RESEED_UNLOCK(x) mtx_unlock(&other_mtx) +#define RANDOM_RESEED_ASSERT_LOCK_OWNED(x) +#endif + +#endif /* SYS_DEV_RANDOM_OTHER_H_INCLUDED */ Modified: head/sys/dev/random/random_harvestq.c ============================================================================== --- head/sys/dev/random/random_harvestq.c Mon Aug 17 05:59:36 2015 (r286838) +++ head/sys/dev/random/random_harvestq.c Mon Aug 17 07:36:12 2015 (r286839) @@ -47,12 +47,21 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/unistd.h> +#if defined(RANDOM_LOADABLE) +#include <sys/lock.h> +#include <sys/sx.h> +#endif + +#include <machine/atomic.h> #include <machine/cpu.h> #include <dev/random/randomdev.h> #include <dev/random/random_harvestq.h> static void random_kthread(void); +static void random_sources_feed(void); + +static u_int read_rate; /* List for the dynamic sysctls */ static struct sysctl_ctx_list random_clist; @@ -66,7 +75,7 @@ static struct sysctl_ctx_list random_cli #define RANDOM_RING_MAX 1024 #define RANDOM_ACCUM_MAX 8 -/* 1 to let the kernel thread run, 0 to terminate */ +/* 1 to let the kernel thread run, 0 to terminate, -1 to mark completion */ volatile int random_kthread_control; /* @@ -123,13 +132,18 @@ static struct kproc_desc random_proc_kp &harvest_context.hc_kthread_proc, }; - /* Pass the given event straight through to Fortuna/Yarrow/Whatever. */ static __inline void random_harvestq_fast_process_event(struct harvest_event *event) { - if (random_alg_context.ra_event_processor) - random_alg_context.ra_event_processor(event); +#if defined(RANDOM_LOADABLE) + RANDOM_CONFIG_S_LOCK(); + if (p_random_alg_context) +#endif + p_random_alg_context->ra_event_processor(event); +#if defined(RANDOM_LOADABLE) + RANDOM_CONFIG_S_UNLOCK(); +#endif } static void @@ -163,12 +177,58 @@ random_kthread(void) /* XXX: FIX!! This is a *great* place to pass hardware/live entropy to random(9) */ tsleep_sbt(&harvest_context.hc_kthread_proc, 0, "-", SBT_1S/10, 0, C_PREL(1)); } + random_kthread_control = -1; wakeup(&harvest_context.hc_kthread_proc); kproc_exit(0); /* NOTREACHED */ } +/* This happens well after SI_SUB_RANDOM */ SYSINIT(random_device_h_proc, SI_SUB_CREATE_INIT, SI_ORDER_ANY, kproc_start, &random_proc_kp); +/* + * Run through all fast 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. + */ +static void +random_sources_feed(void) +{ + uint32_t entropy[HARVESTSIZE]; + struct random_sources *rrs; + u_int i, n, local_read_rate; + + /* + * Step over all of live entropy sources, and feed their output + * to the system-wide RNG. + */ +#if defined(RANDOM_LOADABLE) + RANDOM_CONFIG_S_LOCK(); + if (p_random_alg_context) { + /* It's an indenting error. Yeah, Yeah. */ +#endif + local_read_rate = atomic_readandclear_32(&read_rate); + LIST_FOREACH(rrs, &source_list, rrs_entries) { + for (i = 0; i < p_random_alg_context->ra_poolcount*(local_read_rate + 1); i++) { + n = rrs->rrs_source->rs_read(entropy, sizeof(entropy)); + KASSERT((n > 0 && n <= sizeof(entropy)), ("very bad return from rs_read (= %d) in %s", n, __func__)); + random_harvest_direct(entropy, n, (n*8)/2, rrs->rrs_source->rs_source); + } + } + explicit_bzero(entropy, sizeof(entropy)); +#if defined(RANDOM_LOADABLE) + } + RANDOM_CONFIG_S_UNLOCK(); +#endif +} + +void +read_rate_increment(u_int chunk) +{ + + atomic_add_32(&read_rate, chunk); +} + /* ARGSUSED */ RANDOM_CHECK_UINT(harvestmask, 0, RANDOM_HARVEST_EVERYTHING_MASK); @@ -317,7 +377,8 @@ random_harvestq_deinit(void *unused __un /* Command the hash/reseed thread to end and wait for it to finish */ random_kthread_control = 0; - tsleep(&harvest_context.hc_kthread_proc, 0, "harvqterm", 0); + while (random_kthread_control >= 0) + tsleep(&harvest_context.hc_kthread_proc, 0, "harvqterm", hz/5); sysctl_ctx_free(&random_clist); } SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_deinit, NULL); @@ -412,3 +473,5 @@ random_harvest_direct(const void *entrop random_harvestq_fast_process_event(&event); explicit_bzero(&event, sizeof(event)); } + +MODULE_VERSION(random_harvestq, 1); Modified: head/sys/dev/random/random_harvestq.h ============================================================================== --- head/sys/dev/random/random_harvestq.h Mon Aug 17 05:59:36 2015 (r286838) +++ head/sys/dev/random/random_harvestq.h Mon Aug 17 07:36:12 2015 (r286839) @@ -43,6 +43,8 @@ struct harvest_event { uint8_t he_source; /* origin of the entropy */ } __packed; +void read_rate_increment(u_int); + #define RANDOM_HARVESTQ_BOOT_ENTROPY_FILE "/boot/entropy" #define RANDOM_HARVEST_INIT_LOCK(x) mtx_init(&harvest_context.hc_mtx, "entropy harvest mutex", NULL, MTX_SPIN) Added: head/sys/dev/random/random_infra.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/random/random_infra.c Mon Aug 17 07:36:12 2015 (r286839) @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 2015 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 <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/random.h> +#include <sys/sysctl.h> + +#if defined(RANDOM_LOADABLE) +#include <sys/lock.h> +#include <sys/sx.h> +#endif + +#include <dev/random/randomdev.h> + +/* Set up the sysctl root node for the entropy device */ +SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Cryptographically Secure Random Number Generator"); + +MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); + +struct sources_head source_list = LIST_HEAD_INITIALIZER(source_list); + +#if defined(RANDOM_LOADABLE) +struct random_algorithm *p_random_alg_context = NULL; +#else /* !defined(RANDOM_LOADABLE) */ +struct random_algorithm *p_random_alg_context = &random_alg_context; +#endif /* defined(RANDOM_LOADABLE) */ + +#if defined(RANDOM_LOADABLE) + +struct random_readers { + int (*read_random_uio)(struct uio *, bool); + u_int (*read_random)(void *, u_int); +} random_reader_context = { + (int (*)(struct uio *, bool))nullop, + (u_int (*)(void *, u_int))nullop, +}; + +struct sx randomdev_config_lock; + +static void +random_infra_sysinit(void *dummy __unused) +{ + + RANDOM_CONFIG_INIT_LOCK(); +} +SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_FIRST, random_infra_sysinit, NULL); + +void +random_infra_init(int (*p_random_read_uio)(struct uio *, bool), u_int (*p_random_read)(void *, u_int)) +{ + + RANDOM_CONFIG_X_LOCK(); + random_reader_context.read_random_uio = p_random_read_uio; + random_reader_context.read_random = p_random_read; + RANDOM_CONFIG_X_UNLOCK(); +} + +void +random_infra_uninit(void) +{ + + RANDOM_CONFIG_X_LOCK(); + random_reader_context.read_random_uio = (int (*)(struct uio *, bool))nullop; + random_reader_context.read_random = (u_int (*)(void *, u_int))nullop; + RANDOM_CONFIG_X_UNLOCK(); +} + +static void +random_infra_sysuninit(void *dummy __unused) +{ + + RANDOM_CONFIG_DEINIT_LOCK(); +} +SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_FIRST, random_infra_sysuninit, NULL); + +int +read_random_uio(struct uio *uio, bool nonblock) +{ + int retval; + + RANDOM_CONFIG_S_LOCK(); + retval = random_reader_context.read_random_uio(uio, nonblock); + RANDOM_CONFIG_S_UNLOCK(); + return (retval); +} + +u_int +read_random(void *buf, u_int len) +{ + u_int retval; + + RANDOM_CONFIG_S_LOCK(); + retval = random_reader_context.read_random(buf, len); + RANDOM_CONFIG_S_UNLOCK(); + return (retval); +} + +#endif /* defined(RANDOM_LOADABLE) */ Modified: head/sys/dev/random/randomdev.c ============================================================================== --- head/sys/dev/random/randomdev.c Mon Aug 17 05:59:36 2015 (r286838) +++ head/sys/dev/random/randomdev.c Mon Aug 17 07:36:12 2015 (r286839) @@ -56,14 +56,18 @@ __FBSDID("$FreeBSD$"); #include <dev/random/randomdev.h> #include <dev/random/random_harvestq.h> -#include "opt_random.h" +#define RANDOM_UNIT 0 -#if defined(RANDOM_DUMMY) && defined(RANDOM_YARROW) -#error "Cannot define both RANDOM_DUMMY and RANDOM_YARROW" +#if defined(RANDOM_LOADABLE) +#define READ_RANDOM_UIO _read_random_uio +#define READ_RANDOM _read_random +static int READ_RANDOM_UIO(struct uio *, bool); +static u_int READ_RANDOM(void *, u_int); +#else +#define READ_RANDOM_UIO read_random_uio +#define READ_RANDOM read_random #endif -#define RANDOM_UNIT 0 - /* Return the largest number >= x that is a multiple of m */ #define CEIL_TO_MULTIPLE(x, m) ((((x) + (m) - 1)/(m))*(m)) @@ -84,68 +88,31 @@ static struct cdevsw random_cdevsw = { /* For use with make_dev(9)/destroy_dev(9). */ static struct cdev *random_dev; -/* Set up the sysctl root node for the entropy device */ -SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Cryptographically Secure Random Number Generator"); - -MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); - -#if defined(RANDOM_DUMMY) - -/*- - * Dummy "always block" pseudo algorithm, used when there is no real - * random(4) driver to provide a CSPRNG. - */ - -static u_int -dummy_random_zero(void) -{ - - return (0); -} - -static void -dummy_random(void) -{ -} - -struct random_algorithm random_alg_context = { - .ra_ident = "Dummy", - .ra_init_alg = NULL, - .ra_deinit_alg = NULL, - .ra_pre_read = dummy_random, - .ra_read = (random_alg_read_t *)dummy_random_zero, - .ra_write = (random_alg_write_t *)dummy_random_zero, - .ra_reseed = dummy_random, - .ra_seeded = (random_alg_seeded_t *)dummy_random_zero, - .ra_event_processor = NULL, - .ra_poolcount = 0, -}; - -#else /* !defined(RANDOM_DUMMY) */ - -LIST_HEAD(sources_head, random_sources); -static struct sources_head source_list = LIST_HEAD_INITIALIZER(source_list); -static u_int read_rate; - static void random_alg_context_ra_init_alg(void *data) { - random_alg_context.ra_init_alg(data); + p_random_alg_context = &random_alg_context; + p_random_alg_context->ra_init_alg(data); +#if defined(RANDOM_LOADABLE) + random_infra_init(READ_RANDOM_UIO, READ_RANDOM); +#endif } static void random_alg_context_ra_deinit_alg(void *data) { - random_alg_context.ra_deinit_alg(data); +#if defined(RANDOM_LOADABLE) + random_infra_uninit(); +#endif + p_random_alg_context->ra_deinit_alg(data); + p_random_alg_context = NULL; } SYSINIT(random_device, SI_SUB_RANDOM, SI_ORDER_THIRD, random_alg_context_ra_init_alg, NULL); SYSUNINIT(random_device, SI_SUB_RANDOM, SI_ORDER_THIRD, random_alg_context_ra_deinit_alg, NULL); -#endif /* defined(RANDOM_DUMMY) */ - static struct selinfo rsel; /* @@ -156,28 +123,28 @@ static int randomdev_read(struct cdev *dev __unused, struct uio *uio, int flags) { - return (read_random_uio(uio, (flags & O_NONBLOCK) != 0)); + return (READ_RANDOM_UIO(uio, (flags & O_NONBLOCK) != 0)); } int -read_random_uio(struct uio *uio, bool nonblock) +READ_RANDOM_UIO(struct uio *uio, bool nonblock) { uint8_t *random_buf; int error, spamcount; ssize_t read_len, total_read, c; random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); - random_alg_context.ra_pre_read(); + p_random_alg_context->ra_pre_read(); error = 0; spamcount = 0; /* (Un)Blocking logic */ - while (!random_alg_context.ra_seeded()) { + while (!p_random_alg_context->ra_seeded()) { if (nonblock) { error = EWOULDBLOCK; break; } /* keep tapping away at the pre-read until we seed/unblock. */ - random_alg_context.ra_pre_read(); + p_random_alg_context->ra_pre_read(); /* Only bother the console every 10 seconds or so */ if (spamcount == 0) printf("random: %s unblock wait\n", __func__); @@ -187,10 +154,7 @@ read_random_uio(struct uio *uio, bool no break; } if (error == 0) { -#if !defined(RANDOM_DUMMY) - /* XXX: FIX!! Next line as an atomic operation? */ - read_rate += (uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t); -#endif + read_rate_increment((uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t)); total_read = 0; while (uio->uio_resid && !error) { read_len = uio->uio_resid; @@ -203,7 +167,7 @@ read_random_uio(struct uio *uio, bool no read_len = CEIL_TO_MULTIPLE(read_len, RANDOM_BLOCKSIZE); /* Work in chunks page-sized or less */ read_len = MIN(read_len, PAGE_SIZE); - random_alg_context.ra_read(random_buf, read_len); + p_random_alg_context->ra_read(random_buf, read_len); c = MIN(uio->uio_resid, read_len); error = uiomove(random_buf, c, uio); total_read += c; @@ -224,19 +188,16 @@ read_random_uio(struct uio *uio, bool no * RANDOM_BLOCKSIZE bytes. */ u_int -read_random(void *random_buf, u_int len) +READ_RANDOM(void *random_buf, u_int len) { u_int read_len; uint8_t local_buf[len + RANDOM_BLOCKSIZE]; KASSERT(random_buf != NULL, ("No suitable random buffer in %s", __func__)); - random_alg_context.ra_pre_read(); + p_random_alg_context->ra_pre_read(); /* (Un)Blocking logic; if not seeded, return nothing. */ - if (random_alg_context.ra_seeded()) { -#if !defined(RANDOM_DUMMY) - /* XXX: FIX!! Next line as an atomic operation? */ - read_rate += (len + sizeof(uint32_t))/sizeof(uint32_t); -#endif + if (p_random_alg_context->ra_seeded()) { + read_rate_increment((len + sizeof(uint32_t))/sizeof(uint32_t)); *** DIFF OUTPUT TRUNCATED AT 1000 LINES *** _______________________________________________ svn-src-all@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"