svn commit: r286839 - in head: . share/man/man4 sys/conf sys/dev/random sys/modules sys/modules/random_fortuna sys/modules/random_other sys/modules/random_yarrow sys/sys

Mark Murray markm at FreeBSD.org
Mon Aug 17 07:36:16 UTC 2015


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, &timestamp, sizeof(timestamp));
-	randomdev_hash_iterate(&hash, buf, count);
-	timestamp = (uint32_t)get_cyclecount();
-	randomdev_hash_iterate(&hash, &timestamp, 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 ***


More information about the svn-src-head mailing list