summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Murray <markm@FreeBSD.org>2015-08-17 07:36:12 +0000
committerMark Murray <markm@FreeBSD.org>2015-08-17 07:36:12 +0000
commit646041a89aeab0d79fa350c401de57e1c8b85ac2 (patch)
tree607f453932abecc199a5542abc16308de508677e
parent7a40703db93b4c09f516a89084d01faa533ed195 (diff)
downloadsrc-test2-646041a89aeab0d79fa350c401de57e1c8b85ac2.tar.gz
src-test2-646041a89aeab0d79fa350c401de57e1c8b85ac2.zip
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)
Notes
Notes: svn path=/head/; revision=286839
-rw-r--r--UPDATING15
-rw-r--r--share/man/man4/random.451
-rw-r--r--sys/conf/NOTES7
-rw-r--r--sys/conf/files20
-rw-r--r--sys/conf/options12
-rw-r--r--sys/dev/random/fortuna.c45
-rw-r--r--sys/dev/random/other_algorithm.c209
-rw-r--r--sys/dev/random/other_algorithm.h62
-rw-r--r--sys/dev/random/random_harvestq.c73
-rw-r--r--sys/dev/random/random_harvestq.h2
-rw-r--r--sys/dev/random/random_infra.c128
-rw-r--r--sys/dev/random/randomdev.c181
-rw-r--r--sys/dev/random/randomdev.h38
-rw-r--r--sys/dev/random/randomdev_none.c72
-rw-r--r--sys/dev/random/unit_test.c32
-rw-r--r--sys/dev/random/yarrow.c63
-rw-r--r--sys/modules/Makefile6
-rw-r--r--sys/modules/random_fortuna/Makefile11
-rw-r--r--sys/modules/random_other/Makefile11
-rw-r--r--sys/modules/random_yarrow/Makefile11
-rw-r--r--sys/sys/random.h31
21 files changed, 718 insertions, 362 deletions
diff --git a/UPDATING b/UPDATING
index cf93fa5b5df2..5464745a9a84 100644
--- a/UPDATING
+++ b/UPDATING
@@ -31,6 +31,21 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 11.x IS SLOW:
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
diff --git a/share/man/man4/random.4 b/share/man/man4/random.4
index 133fb3bb52a8..75a727460586 100644
--- a/share/man/man4/random.4
+++ b/share/man/man4/random.4
@@ -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.
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index b0619cbc4469..7bc20483dfc3 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -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
diff --git a/sys/conf/files b/sys/conf/files
index b8438ce3f069..dfe9763568fb 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -550,14 +550,14 @@ crypto/des/des_ecb.c optional crypto | ipsec | netsmb
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
diff --git a/sys/conf/options b/sys/conf/options
index bf6c4a6e9769..30bbc53bd5a2 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -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
diff --git a/sys/dev/random/fortuna.c b/sys/dev/random/fortuna.c
index 2aafba4217e5..0b03931b5e3f 100644
--- a/sys/dev/random/fortuna.c
+++ b/sys/dev/random/fortuna.c
@@ -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_BLOCKSIZE];
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_context = {
.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 bytecount)
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)
{
diff --git a/sys/dev/random/other_algorithm.c b/sys/dev/random/other_algorithm.c
new file mode 100644
index 000000000000..740e879a6d6d
--- /dev/null
+++ b/sys/dev/random/other_algorithm.c
@@ -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();
+}
diff --git a/sys/dev/random/other_algorithm.h b/sys/dev/random/other_algorithm.h
new file mode 100644
index 000000000000..8ca2bb89b39e
--- /dev/null
+++ b/sys/dev/random/other_algorithm.h
@@ -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 */
diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c
index 34a809be00f9..255136c03ae2 100644
--- a/sys/dev/random/random_harvestq.c
+++ b/sys/dev/random/random_harvestq.c
@@ -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_clist;
#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 __unused)
/* 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 *entropy, u_int size, u_int bits, enum random_e
random_harvestq_fast_process_event(&event);
explicit_bzero(&event, sizeof(event));
}
+
+MODULE_VERSION(random_harvestq, 1);
diff --git a/sys/dev/random/random_harvestq.h b/sys/dev/random/random_harvestq.h
index f1de86f07add..421b592d9243 100644
--- a/sys/dev/random/random_harvestq.h
+++ b/sys/dev/random/random_harvestq.h
@@ -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)
diff --git a/sys/dev/random/random_infra.c b/sys/dev/random/random_infra.c
new file mode 100644
index 000000000000..d31b84b24582
--- /dev/null
+++ b/sys/dev/random/random_infra.c
@@ -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) */
diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c
index 5c20c5d53452..f20a462904f2 100644
--- a/sys/dev/random/randomdev.c
+++ b/sys/dev/random/randomdev.c
@@ -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 nonblock)
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 nonblock)
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 nonblock)
* 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));
if (len > 0) {
/*
* Belt-and-braces.
@@ -244,7 +205,7 @@ read_random(void *random_buf, u_int len)
* which is what the underlying generator is expecting.
*/
read_len = CEIL_TO_MULTIPLE(len, RANDOM_BLOCKSIZE);
- random_alg_context.ra_read(local_buf, read_len);
+ p_random_alg_context->ra_read(local_buf, read_len);
memcpy(random_buf, local_buf, len);
}
} else
@@ -252,6 +213,37 @@ read_random(void *random_buf, u_int len)
return (len);
}
+static __inline void
+randomdev_accumulate(uint8_t *buf, u_int count)
+{
+ static u_int destination = 0;
+ static struct harvest_event event;
+ static struct randomdev_hash hash;
+ static uint32_t entropy_data[RANDOM_KEYSIZE_WORDS];
+ uint32_t timestamp;
+ int i;
+
+ /* Extra timing here is helpful to scrape scheduler jitter 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));
+ p_random_alg_context->ra_event_processor(&event);
+ }
+ explicit_bzero(entropy_data, sizeof(entropy_data));
+}
+
/* ARGSUSED */
static int
randomdev_write(struct cdev *dev __unused, struct uio *uio, int flags __unused)
@@ -267,7 +259,7 @@ randomdev_write(struct cdev *dev __unused, struct uio *uio, int flags __unused)
error = uiomove(random_buf, c, uio);
if (error)
break;
- random_alg_context.ra_write(random_buf, c);
+ randomdev_accumulate(random_buf, c);
tsleep(&random_alg_context, 0, "randwr", hz/10);
}
if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR))
@@ -283,7 +275,7 @@ randomdev_poll(struct cdev *dev __unused, int events, struct thread *td __unused
{
if (events & (POLLIN | POLLRDNORM)) {
- if (random_alg_context.ra_seeded())
+ if (p_random_alg_context->ra_seeded())
events &= (POLLIN | POLLRDNORM);
else
selrecord(td, &rsel);
@@ -325,9 +317,6 @@ randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
void
random_source_register(struct random_source *rsource)
{
-#if defined(RANDOM_DUMMY)
- (void)rsource;
-#else /* !defined(RANDOM_DUMMY) */
struct random_sources *rrs;
KASSERT(rsource != NULL, ("invalid input to %s", __func__));
@@ -337,15 +326,11 @@ random_source_register(struct random_source *rsource)
printf("random: registering fast source %s\n", rsource->rs_ident);
LIST_INSERT_HEAD(&source_list, rrs, rrs_entries);
-#endif /* defined(RANDOM_DUMMY) */
}
void
random_source_deregister(struct random_source *rsource)
{
-#if defined(RANDOM_DUMMY)
- (void)rsource;
-#else /* !defined(RANDOM_DUMMY) */
struct random_sources *rrs = NULL;
KASSERT(rsource != NULL, ("invalid input to %s", __func__));
@@ -356,41 +341,6 @@ random_source_deregister(struct random_source *rsource)
}
if (rrs != NULL)
free(rrs, M_ENTROPY);
-#endif /* defined(RANDOM_DUMMY) */
-}
-
-#if !defined(RANDOM_DUMMY)
-/*
- * 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.
- *
- * BEWARE!!!
- * This function runs inside the RNG thread! Don't do anything silly!
- */
-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.
- */
- /* XXX: FIX!! Next lines as an atomic operation? */
- local_read_rate = read_rate;
- read_rate = RANDOM_ALG_READ_RATE_MINIMUM;
- LIST_FOREACH(rrs, &source_list, rrs_entries) {
- for (i = 0; i < random_alg_context.ra_poolcount*local_read_rate; 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));
}
static int
@@ -414,7 +364,6 @@ random_source_handler(SYSCTL_HANDLER_ARGS)
SYSCTL_PROC(_kern_random, OID_AUTO, random_sources, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
NULL, 0, random_source_handler, "A",
"List of active fast entropy sources.");
-#endif /* !defined(RANDOM_DUMMY) */
/* ARGSUSED */
static int
@@ -449,3 +398,5 @@ static moduledata_t randomdev_mod = {
DECLARE_MODULE(random_device, randomdev_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
MODULE_VERSION(random_device, 1);
+MODULE_DEPEND(random_device, crypto, 1, 1, 1);
+MODULE_DEPEND(random_device, random_harvestq, 1, 1, 1);
diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h
index 799efb1b0612..0f3b359d1f1f 100644
--- a/sys/dev/random/randomdev.h
+++ b/sys/dev/random/randomdev.h
@@ -55,16 +55,15 @@ random_check_uint_##name(SYSCTL_HANDLER_ARGS) \
MALLOC_DECLARE(M_ENTROPY);
-#define RANDOM_ALG_READ_RATE_MINIMUM 32
-
#endif /* _KERNEL */
struct harvest_event;
+typedef void random_alg_init_t(void *);
+typedef void random_alg_deinit_t(void *);
typedef void random_alg_pre_read_t(void);
typedef void random_alg_read_t(uint8_t *, u_int);
-typedef void random_alg_write_t(uint8_t *, u_int);
-typedef int random_alg_seeded_t(void);
+typedef bool random_alg_seeded_t(void);
typedef void random_alg_reseed_t(void);
typedef void random_alg_eventprocessor_t(struct harvest_event *);
@@ -81,13 +80,11 @@ struct random_algorithm {
void (*ra_deinit_alg)(void *);
random_alg_pre_read_t *ra_pre_read;
random_alg_read_t *ra_read;
- random_alg_write_t *ra_write;
- random_alg_reseed_t *ra_reseed;
random_alg_seeded_t *ra_seeded;
random_alg_eventprocessor_t *ra_event_processor;
};
-extern struct random_algorithm random_alg_context;
+extern struct random_algorithm random_alg_context, *p_random_alg_context;
#ifdef _KERNEL
@@ -97,22 +94,33 @@ extern struct random_algorithm random_alg_context;
* upon request.
*/
struct random_source {
- const char *rs_ident;
- enum random_entropy_source rs_source;
- random_source_read_t *rs_read;
+ const char *rs_ident;
+ enum random_entropy_source rs_source;
+ random_source_read_t *rs_read;
};
-#if !defined(RANDOM_DUMMY)
struct random_sources {
- LIST_ENTRY(random_sources) rrs_entries;
- struct random_source *rrs_source;
+ LIST_ENTRY(random_sources) rrs_entries;
+ struct random_source *rrs_source;
};
-#endif /* !defined(RANDOM_DUMMY) */
+
+LIST_HEAD(sources_head, random_sources);
+extern struct sources_head source_list;
void random_source_register(struct random_source *);
void random_source_deregister(struct random_source *);
-void random_sources_feed(void);
+#if defined(RANDOM_LOADABLE)
+extern struct sx randomdev_config_lock;
+#define RANDOM_CONFIG_INIT_LOCK(x) sx_init(&randomdev_config_lock, "configuration change lock")
+#define RANDOM_CONFIG_X_LOCK(x) sx_xlock(&randomdev_config_lock)
+#define RANDOM_CONFIG_X_UNLOCK(x) sx_xunlock(&randomdev_config_lock)
+#define RANDOM_CONFIG_S_LOCK(x) sx_slock(&randomdev_config_lock)
+#define RANDOM_CONFIG_S_UNLOCK(x) sx_sunlock(&randomdev_config_lock)
+#define RANDOM_CONFIG_DEINIT_LOCK(x) sx_destroy(&randomdev_config_lock)
+void random_infra_init(int (*)(struct uio *, bool), u_int (*)(void *, u_int));
+void random_infra_uninit(void);
+#endif
#endif /* _KERNEL */
diff --git a/sys/dev/random/randomdev_none.c b/sys/dev/random/randomdev_none.c
deleted file mode 100644
index ee5cbf2b4417..000000000000
--- a/sys/dev/random/randomdev_none.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*-
- * 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/malloc.h>
-#include <sys/random.h>
-#include <sys/systm.h>
-
-#include <dev/random/randomdev.h>
-
-#include "opt_random.h"
-
-#if defined(RANDOM_DUMMY) || defined(RANDOM_YARROW)
-#error "Cannot define any of RANDOM_DUMMY and RANDOM_YARROW without 'device random'"
-#endif
-
-/*-
- * Dummy "not even here" device. Stub out all routines that the kernel would need.
- */
-
-/* ARGSUSED */
-u_int
-read_random(void *random_buf __unused, u_int len __unused)
-{
-
- return (0);
-}
-
-/* ARGSUSED */
-void
-random_harvest_direct(const void *entropy __unused, u_int count __unused, u_int bits __unused, enum random_entropy_source origin __unused)
-{
-}
-
-/* ARGSUSED */
-void
-random_harvest_queue(const void *entropy __unused, u_int count __unused, u_int bits __unused, enum random_entropy_source origin __unused)
-{
-}
-
-/* ARGSUSED */
-void
-random_harvest_fast(const void *entropy __unused, u_int count __unused, u_int bits __unused, enum random_entropy_source origin __unused)
-{
-}
diff --git a/sys/dev/random/unit_test.c b/sys/dev/random/unit_test.c
index 7ae571677049..fac4c8d77d3c 100644
--- a/sys/dev/random/unit_test.c
+++ b/sys/dev/random/unit_test.c
@@ -46,6 +46,7 @@ Where <alg> is YARROW or FORTUNA.
#include <sys/types.h>
#include <inttypes.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <threads.h>
@@ -172,35 +173,6 @@ RunHarvester(void *arg __unused)
}
static int
-WriteCSPRNG(void *threadid)
-{
- uint8_t *buf;
- int i;
-
- printf("Thread #1 starts\n");
-
- for (i = 0; ; i++) {
- if (stopseeding)
- break;
- buf = malloc(4096);
- if (i % 1000 == 0)
- printf("Thread write 1 - %d\n", i);
- if (buf != NULL) {
- printf("Thread 1 writing.\n");
- random_alg_context.ra_write(buf, i);
- free(buf);
- }
- usleep(1000000);
- }
-
- printf("Thread #1 ends\n");
-
- thrd_exit(0);
-
- return (0);
-}
-
-static int
ReadCSPRNG(void *threadid)
{
size_t tid, zsize;
@@ -271,7 +243,7 @@ main(int argc, char *argv[])
for (t = 0; t < NUM_THREADS; t++) {
printf("In main: creating thread %ld\n", t);
- rc = thrd_create(&threads[t], (t == 0 ? RunHarvester : (t == 1 ? WriteCSPRNG : ReadCSPRNG)), NULL);
+ rc = thrd_create(&threads[t], (t == 0 ? RunHarvester : ReadCSPRNG), NULL);
if (rc != thrd_success) {
printf("ERROR; return code from thrd_create() is %d\n", rc);
exit(-1);
diff --git a/sys/dev/random/yarrow.c b/sys/dev/random/yarrow.c
index d6ebd46102ca..2ef15a4acde9 100644
--- a/sys/dev/random/yarrow.c
+++ b/sys/dev/random/yarrow.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include <dev/random/yarrow.h>
#else /* !_KERNEL */
#include <inttypes.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@@ -92,7 +93,7 @@ static struct yarrow_state {
u_int ysp_thresh; /* pool reseed threshhold */
struct randomdev_hash ysp_hash; /* accumulated entropy */
} ys_pool[RANDOM_YARROW_NPOOLS];/* pool[0] is fast, pool[1] is slow */
- int ys_seeded;
+ bool ys_seeded;
/* Reseed lock */
mtx_t ys_mtx;
} yarrow_state;
@@ -108,9 +109,7 @@ RANDOM_CHECK_UINT(slowoverthresh, 1, 5);
static void random_yarrow_pre_read(void);
static void random_yarrow_read(uint8_t *, u_int);
-static void random_yarrow_write(uint8_t *, u_int);
-static void random_yarrow_reseed(void);
-static int random_yarrow_seeded(void);
+static bool random_yarrow_seeded(void);
static void random_yarrow_process_event(struct harvest_event *);
static void random_yarrow_init_alg(void *);
static void random_yarrow_deinit_alg(void *);
@@ -123,8 +122,6 @@ struct random_algorithm random_alg_context = {
.ra_deinit_alg = random_yarrow_deinit_alg,
.ra_pre_read = random_yarrow_pre_read,
.ra_read = random_yarrow_read,
- .ra_write = random_yarrow_write,
- .ra_reseed = random_yarrow_reseed,
.ra_seeded = random_yarrow_seeded,
.ra_event_processor = random_yarrow_process_event,
.ra_poolcount = RANDOM_YARROW_NPOOLS,
@@ -141,7 +138,7 @@ random_yarrow_init_alg(void *unused __unused)
RANDOM_RESEED_INIT_LOCK();
/* Start unseeded, therefore blocked. */
- yarrow_state.ys_seeded = 0;
+ yarrow_state.ys_seeded = false;
#ifdef _KERNEL
/*
* Yarrow parameters. Do not adjust these unless you have
@@ -266,12 +263,14 @@ random_yarrow_reseed_internal(u_int fastslow)
RANDOM_RESEED_ASSERT_LOCK_OWNED();
#ifdef RANDOM_DEBUG
/* WARNING! This is dangerously tedious to do with mutexes held! */
- printf("random: %s %s seeded = %d\n", __func__, (fastslow == RANDOM_YARROW_FAST ? "RANDOM_YARROW_FAST" : "RANDOM_YARROW_SLOW"), yarrow_state.ys_seeded);
- printf("random: %s - fast - thresh %d,1 - ", __func__, yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_thresh);
+ printf("random: %s ", __func__);
+ printf("type/pool = %s ", fastslow == RANDOM_YARROW_FAST ? "RANDOM_YARROW_FAST" : "RANDOM_YARROW_SLOW");
+ printf("seeded = %s\n", yarrow_state.ys_seeded ? "true" : "false");
+ printf("random: fast - thresh %d,1 - ", yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_thresh);
for (i = RANDOM_START; i < ENTROPYSOURCE; i++)
printf(" %d", yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_source_bits[i]);
printf("\n");
- printf("random: %s - slow - thresh %d,%d - ", __func__, yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_thresh, yarrow_state.ys_slowoverthresh);
+ printf("random: slow - thresh %d,%d - ", yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_thresh, yarrow_state.ys_slowoverthresh);
for (i = RANDOM_START; i < ENTROPYSOURCE; i++)
printf(" %d", yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_source_bits[i]);
printf("\n");
@@ -338,7 +337,7 @@ random_yarrow_reseed_internal(u_int fastslow)
#endif
/* Unblock the device if it was blocked due to being unseeded */
if (!yarrow_state.ys_seeded) {
- yarrow_state.ys_seeded = 1;
+ yarrow_state.ys_seeded = true;
randomdev_unblock();
}
}
@@ -395,47 +394,7 @@ random_yarrow_read(uint8_t *buf, u_int bytecount)
RANDOM_RESEED_UNLOCK();
}
-/* Internal function to hand external entropy to the PRNG. */
-void
-random_yarrow_write(uint8_t *buf, u_int count)
-{
- static u_int destination = 0;
- static 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_yarrow_process_event(&event);
- }
- explicit_bzero(entropy_data, sizeof(entropy_data));
-}
-
-void
-random_yarrow_reseed(void)
-{
-
- RANDOM_RESEED_LOCK();
- random_yarrow_reseed_internal(RANDOM_YARROW_SLOW);
- RANDOM_RESEED_UNLOCK();
-}
-
-int
+bool
random_yarrow_seeded(void)
{
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index bd523563edf6..21009a9a4ec5 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -296,6 +296,9 @@ SUBDIR= \
${_qlxgbe} \
ral \
${_ralfw} \
+ ${_random_fortuna} \
+ ${_random_yarrow} \
+ ${_random_other} \
rc4 \
${_rdma} \
${_rdrand_rng} \
@@ -398,6 +401,9 @@ _autofs= autofs
.if exists(${.CURDIR}/../opencrypto)
_crypto= crypto
_cryptodev= cryptodev
+_random_fortuna=random_fortuna
+_random_yarrow= random_yarrow
+_random_other= random_other
.endif
.endif
diff --git a/sys/modules/random_fortuna/Makefile b/sys/modules/random_fortuna/Makefile
new file mode 100644
index 000000000000..d28ae4d291dd
--- /dev/null
+++ b/sys/modules/random_fortuna/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/random
+
+KMOD = random_fortuna
+SRCS = randomdev.c hash.c fortuna.c
+SRCS += opt_param.h bus_if.h device_if.h
+SRCS += opt_ddb.h
+CFLAGS += -DRANDOM_LOADABLE
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/random_other/Makefile b/sys/modules/random_other/Makefile
new file mode 100644
index 000000000000..6ce586bf057b
--- /dev/null
+++ b/sys/modules/random_other/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/random
+
+KMOD = random_OTHER
+SRCS = randomdev.c hash.c other_algorithm.c
+SRCS += opt_param.h bus_if.h device_if.h
+SRCS += opt_ddb.h
+CFLAGS += -DRANDOM_LOADABLE
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/random_yarrow/Makefile b/sys/modules/random_yarrow/Makefile
new file mode 100644
index 000000000000..1750af445500
--- /dev/null
+++ b/sys/modules/random_yarrow/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/random
+
+KMOD = random_yarrow
+SRCS = randomdev.c hash.c yarrow.c
+SRCS += opt_param.h bus_if.h device_if.h
+SRCS += opt_ddb.h
+CFLAGS += -DRANDOM_LOADABLE
+
+.include <bsd.kmod.mk>
diff --git a/sys/sys/random.h b/sys/sys/random.h
index 78a9955a0e10..92eb80feba15 100644
--- a/sys/sys/random.h
+++ b/sys/sys/random.h
@@ -33,10 +33,29 @@
#include <sys/types.h>
+#include "opt_random.h"
+
+#if defined(RANDOM_LOADABLE) && defined(RANDOM_YARROW)
+#error "Cannot define both RANDOM_LOADABLE and RANDOM_YARROW"
+#endif
+
struct uio;
+#if defined(DEV_RANDOM)
u_int read_random(void *, u_int);
int read_random_uio(struct uio *, bool);
+#else
+static __inline int
+read_random_uio(void *a __unused, u_int b __unused)
+{
+ return (0);
+}
+static __inline u_int
+read_random(void *a __unused, u_int b __unused)
+{
+ return (0);
+}
+#endif
/*
* Note: if you add or remove members of random_entropy_source, remember to also update the
@@ -76,15 +95,15 @@ enum random_entropy_source {
#define RANDOM_HARVEST_EVERYTHING_MASK ((1 << (RANDOM_ENVIRONMENTAL_END + 1)) - 1)
-#if defined(RANDOM_DUMMY)
-#define random_harvest_queue(a, b, c, d) do {} while (0)
-#define random_harvest_fast(a, b, c, d) do {} while (0)
-#define random_harvest_direct(a, b, c, d) do {} while (0)
-#else /* !defined(RANDOM_DUMMY) */
+#if defined(DEV_RANDOM)
void random_harvest_queue(const void *, u_int, u_int, enum random_entropy_source);
void random_harvest_fast(const void *, u_int, u_int, enum random_entropy_source);
void random_harvest_direct(const void *, u_int, u_int, enum random_entropy_source);
-#endif /* defined(RANDOM_DUMMY) */
+#else
+#define random_harvest_queue(a, b, c, d) do {} while (0)
+#define random_harvest_fast(a, b, c, d) do {} while (0)
+#define random_harvest_direct(a, b, c, d) do {} while (0)
+#endif
#endif /* _KERNEL */