summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/defaults/rc.conf2
-rw-r--r--etc/rc.d/Makefile1
-rwxr-xr-xetc/rc.d/geli2
-rwxr-xr-xetc/rc.d/initrandom61
-rwxr-xr-xetc/rc.d/postrandom2
-rwxr-xr-xetc/rc.d/random2
-rwxr-xr-xlibexec/save-entropy/save-entropy.sh2
-rw-r--r--share/examples/kld/random_adaptor/random_adaptor_example.c54
-rw-r--r--sys/conf/NOTES6
-rw-r--r--sys/conf/files11
-rw-r--r--sys/conf/options1
-rw-r--r--sys/dev/glxsb/glxsb.c2
-rwxr-xr-xsys/dev/random/build.sh24
-rw-r--r--sys/dev/random/dummy_rng.c121
-rw-r--r--sys/dev/random/fortuna.c433
-rw-r--r--sys/dev/random/fortuna.h (renamed from sys/dev/random/rwfile.h)19
-rw-r--r--sys/dev/random/harvest.c141
-rw-r--r--sys/dev/random/hash.c21
-rw-r--r--sys/dev/random/hash.h2
-rw-r--r--sys/dev/random/ivy.c43
-rw-r--r--sys/dev/random/live_entropy_sources.c145
-rw-r--r--sys/dev/random/live_entropy_sources.h31
-rw-r--r--sys/dev/random/nehemiah.c37
-rw-r--r--sys/dev/random/random_adaptors.c486
-rw-r--r--sys/dev/random/random_adaptors.h61
-rw-r--r--sys/dev/random/random_harvestq.c428
-rw-r--r--sys/dev/random/random_harvestq.h40
-rw-r--r--sys/dev/random/randomdev.c271
-rw-r--r--sys/dev/random/randomdev.h51
-rw-r--r--sys/dev/random/randomdev_soft.c250
-rw-r--r--sys/dev/random/randomdev_soft.h51
-rw-r--r--sys/dev/random/rwfile.c96
-rw-r--r--sys/dev/random/uint128.h75
-rw-r--r--sys/dev/random/unit_test.c257
-rw-r--r--sys/dev/random/unit_test.h72
-rw-r--r--sys/dev/random/yarrow.c523
-rw-r--r--sys/dev/random/yarrow.h11
-rw-r--r--sys/kern/init_main.c2
-rw-r--r--sys/kern/kern_intr.c25
-rw-r--r--sys/kern/subr_bus.c2
-rw-r--r--sys/modules/Makefile15
-rw-r--r--sys/modules/padlock_rng/Makefile11
-rw-r--r--sys/modules/random/Makefile10
-rw-r--r--sys/modules/rdrand_rng/Makefile11
-rw-r--r--sys/net/if_ethersubr.c3
-rw-r--r--sys/net/if_tun.c3
-rw-r--r--sys/netgraph/ng_iface.c3
-rw-r--r--sys/sys/random.h29
-rw-r--r--sys/vm/uma_core.c35
49 files changed, 2460 insertions, 1524 deletions
diff --git a/etc/defaults/rc.conf b/etc/defaults/rc.conf
index 18989fa..79799bf 100644
--- a/etc/defaults/rc.conf
+++ b/etc/defaults/rc.conf
@@ -645,7 +645,7 @@ update_motd="YES" # update version info in /etc/motd (or NO)
entropy_file="/entropy" # Set to NO to disable caching entropy through reboots.
# /var/db/entropy-file is preferred if / is not avail.
entropy_dir="/var/db/entropy" # Set to NO to disable caching entropy via cron.
-entropy_save_sz="2048" # Size of the entropy cache files.
+entropy_save_sz="4096" # Size of the entropy cache files.
entropy_save_num="8" # Number of entropy cache files to save.
harvest_interrupt="YES" # Entropy device harvests interrupt randomness
harvest_ethernet="YES" # Entropy device harvests ethernet randomness
diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile
index 2a3057f..72b5247 100644
--- a/etc/rc.d/Makefile
+++ b/etc/rc.d/Makefile
@@ -57,7 +57,6 @@ FILES= DAEMON \
hostid_save \
hostname \
inetd \
- initrandom \
ip6addrctl \
ipfilter \
ipfs \
diff --git a/etc/rc.d/geli b/etc/rc.d/geli
index 8b867b3..4551f71 100755
--- a/etc/rc.d/geli
+++ b/etc/rc.d/geli
@@ -28,7 +28,7 @@
#
# PROVIDE: disks
-# REQUIRE: initrandom
+# REQUIRE: random
# KEYWORD: nojail
. /etc/rc.subr
diff --git a/etc/rc.d/initrandom b/etc/rc.d/initrandom
deleted file mode 100755
index 907668b..0000000
--- a/etc/rc.d/initrandom
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/bin/sh
-#
-# $FreeBSD$
-#
-
-# PROVIDE: initrandom
-# REQUIRE: dumpon ddb
-# BEFORE: disks
-# KEYWORD: nojail
-
-. /etc/rc.subr
-
-name="initrandom"
-start_cmd="initrandom_start"
-stop_cmd=":"
-
-initrandom_start()
-{
- soft_random_generator=`sysctl kern.random 2>/dev/null`
-
- echo -n 'Entropy harvesting:'
-
- if [ \! -z "${soft_random_generator}" ] ; then
-
- if [ -w /dev/random ]; then
- if checkyesno harvest_interrupt; then
- ${SYSCTL} kern.random.sys.harvest.interrupt=1 >/dev/null
- echo -n ' interrupts'
- else
- ${SYSCTL} kern.random.sys.harvest.interrupt=0 >/dev/null
- fi
-
- if checkyesno harvest_ethernet; then
- ${SYSCTL} kern.random.sys.harvest.ethernet=1 >/dev/null
- echo -n ' ethernet'
- else
- ${SYSCTL} kern.random.sys.harvest.ethernet=0 >/dev/null
- fi
-
- if checkyesno harvest_p_to_p; then
- ${SYSCTL} kern.random.sys.harvest.point_to_point=1 >/dev/null
- echo -n ' point_to_point'
- else
- ${SYSCTL} kern.random.sys.harvest.point_to_point=0 >/dev/null
- fi
-
- if checkyesno harvest_swi; then
- ${SYSCTL} kern.random.sys.harvest.swi=1 >/dev/null
- echo -n ' swi'
- else
- ${SYSCTL} kern.random.sys.harvest.swi=0 >/dev/null
- fi
- fi
-
- fi
-
- echo '.'
-}
-
-load_rc_config random
-run_rc_command "$1"
diff --git a/etc/rc.d/postrandom b/etc/rc.d/postrandom
index 006d563..3a60830 100755
--- a/etc/rc.d/postrandom
+++ b/etc/rc.d/postrandom
@@ -4,7 +4,7 @@
#
# PROVIDE: postrandom
-# REQUIRE: initrandom random FILESYSTEMS
+# REQUIRE: random FILESYSTEMS
# BEFORE: LOGIN
# KEYWORD: nojail
diff --git a/etc/rc.d/random b/etc/rc.d/random
index 8499522..c7da932 100755
--- a/etc/rc.d/random
+++ b/etc/rc.d/random
@@ -4,7 +4,7 @@
#
# PROVIDE: random
-# REQUIRE: initrandom FILESYSTEMS
+# REQUIRE: FILESYSTEMS
# BEFORE: netif
# KEYWORD: nojail shutdown
diff --git a/libexec/save-entropy/save-entropy.sh b/libexec/save-entropy/save-entropy.sh
index 880a988..06319d5 100755
--- a/libexec/save-entropy/save-entropy.sh
+++ b/libexec/save-entropy/save-entropy.sh
@@ -53,7 +53,7 @@ case ${entropy_dir} in
;;
esac
-entropy_save_sz=${entropy_save_sz:-2048}
+entropy_save_sz=${entropy_save_sz:-4096}
entropy_save_num=${entropy_save_num:-8}
if [ ! -d "${entropy_dir}" ]; then
diff --git a/share/examples/kld/random_adaptor/random_adaptor_example.c b/share/examples/kld/random_adaptor/random_adaptor_example.c
index da588a8..34993c1 100644
--- a/share/examples/kld/random_adaptor/random_adaptor_example.c
+++ b/share/examples/kld/random_adaptor/random_adaptor_example.c
@@ -35,17 +35,20 @@ __FBSDID("$FreeBSD$");
#include <sys/random.h>
#include <sys/systm.h>
-#include <dev/random/live_entropy_sources.h>
-#include <dev/random/random_adaptors.h>
#include <dev/random/randomdev.h>
+#include <dev/random/randomdev_soft.h>
+#include <dev/random/random_adaptors.h>
+#include <dev/random/live_entropy_sources.h>
-static int random_example_read(void *, int);
+static void live_random_example_init(void);
+static void live_random_example_deinit(void);
+static u_int live_random_example_read(void *, u_int);
-struct random_adaptor random_example = {
- .ident = "Example RNG",
- .source = RANDOM_PURE_BOGUS, /* Make sure this is in
- * sys/random.h and is unique */
- .read = random_example_read,
+struct random_adaptor live_random_example = {
+ .les_ident = "Example RNG",
+ .les_source = RANDOM_PURE_BOGUS, /* Make sure this is in
+ * sys/random.h and is unique */
+ .les_read = live_random_example_read,
};
/*
@@ -58,8 +61,26 @@ getRandomNumber(void)
return 4; /* chosen by fair dice roll, guaranteed to be random */
}
-static int
-random_example_read(void *buf, int c)
+static void
+live_random_example_init(void)
+{
+
+ /* Do initialisation stuff here */
+}
+
+static void
+live_random_example_deinit(void)
+{
+
+ /* Do de-initialisation stuff here */
+}
+
+/* get <c> bytes of random stuff into <buf>. You may presume
+ * that <c> is a multiple of 2^n, with n>=3. A typical value
+ * is c=16.
+ */
+static u_int
+live_random_example_read(void *buf, u_int c)
{
uint8_t *b;
int count;
@@ -69,22 +90,23 @@ random_example_read(void *buf, int c)
for (count = 0; count < c; count++)
b[count] = getRandomNumber();
- printf("returning %d bytes of pure randomness\n", c);
+ /* printf("returning %d bytes of pure randomness\n", c); */
return (c);
}
+/* ARGSUSED */
static int
-random_example_modevent(module_t mod, int type, void *unused)
+live_random_example_modevent(module_t mod __unused, int type, void *unused __unused)
{
int error = 0;
switch (type) {
case MOD_LOAD:
- live_entropy_source_register(&random_example);
+ live_entropy_source_register(&live_random_example);
break;
case MOD_UNLOAD:
- live_entropy_source_deregister(&random_example);
+ live_entropy_source_deregister(&live_random_example);
break;
case MOD_SHUTDOWN:
@@ -98,4 +120,6 @@ random_example_modevent(module_t mod, int type, void *unused)
return (error);
}
-LIVE_ENTROPY_SRC_MODULE(live_entropy_source_example, random_example_modevent, 1);
+DEV_MODULE(live_random_example, live_random_example_modevent, NULL);
+MODULE_VERSION(live_random_example, 1);
+MODULE_DEPEND(live_random_example, randomdev, 1, 1, 1);
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 4eb25d5..513300c 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -2993,10 +2993,10 @@ options BROOKTREE_ALLOC_PAGES=(217*4+1)
options MAXFILES=999
# Random number generator
-options RANDOM_YARROW # Yarrow RNG
-##options RANDOM_FORTUNA # Fortuna RNG - not yet implemented
+# Only ONE of the below two may be used; they are mutually exclusive.
+options RANDOM_YARROW # Yarrow CSPRNG (Default)
+#options RANDOM_FORTUNA # Fortuna CSPRNG
options RANDOM_DEBUG # Debugging messages
-options RANDOM_RWFILE # Read and write entropy cache
# Module to enable execution of application via emulators like QEMU
options IMAGACT_BINMISC
diff --git a/sys/conf/files b/sys/conf/files
index 3e89dbb..7abcc66 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -2132,16 +2132,15 @@ rt2860.fw optional rt2860fw | ralfw \
compile-with "${NORMAL_FW}" \
no-obj no-implicit-rule \
clean "rt2860.fw"
-dev/random/harvest.c standard
-dev/random/dummy_rng.c standard
+dev/random/randomdev.c standard
dev/random/random_adaptors.c standard
-dev/random/live_entropy_sources.c optional random
-dev/random/random_harvestq.c optional random
-dev/random/randomdev.c optional random
+dev/random/dummy_rng.c standard
+dev/random/live_entropy_sources.c standard
+dev/random/random_harvestq.c standard
dev/random/randomdev_soft.c optional random
dev/random/yarrow.c optional random
+dev/random/fortuna.c optional random
dev/random/hash.c optional random
-dev/random/rwfile.c optional random
dev/rc/rc.c optional rc
dev/re/if_re.c optional re
dev/rl/if_rl.c optional rl pci
diff --git a/sys/conf/options b/sys/conf/options
index f6ad35a..ae0f852 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -930,4 +930,3 @@ RCTL opt_global.h
RANDOM_YARROW opt_random.h
RANDOM_FORTUNA opt_random.h
RANDOM_DEBUG opt_random.h
-RANDOM_RWFILE opt_random.h
diff --git a/sys/dev/glxsb/glxsb.c b/sys/dev/glxsb/glxsb.c
index 646fe3f..9a467ed 100644
--- a/sys/dev/glxsb/glxsb.c
+++ b/sys/dev/glxsb/glxsb.c
@@ -476,7 +476,7 @@ glxsb_rnd(void *v)
if (status & SB_RNS_TRNG_VALID) {
value = bus_read_4(sc->sc_sr, SB_RANDOM_NUM);
/* feed with one uint32 */
- random_harvest(&value, 4, 32/2, RANDOM_PURE_GLXSB);
+ random_harvest(&value, sizeof(value), 32/2, RANDOM_PURE_GLXSB);
}
callout_reset(&sc->sc_rngco, sc->sc_rnghz, glxsb_rnd, sc);
diff --git a/sys/dev/random/build.sh b/sys/dev/random/build.sh
new file mode 100755
index 0000000..e573dc1
--- /dev/null
+++ b/sys/dev/random/build.sh
@@ -0,0 +1,24 @@
+# $FreeBSD$
+#
+# Basic script to build crude unit tests.
+#
+cc -g -O0 -pthread -DRANDOM_DEBUG -DRANDOM_YARROW \
+ -I../.. -lstdthreads -Wall \
+ unit_test.c \
+ yarrow.c \
+ hash.c \
+ ../../crypto/rijndael/rijndael-api-fst.c \
+ ../../crypto/rijndael/rijndael-alg-fst.c \
+ ../../crypto/sha2/sha2.c \
+ ../../crypto/sha2/sha256c.c \
+ -o yunit_test
+cc -g -O0 -pthread -DRANDOM_DEBUG -DRANDOM_FORTUNA \
+ -I../.. -lstdthreads -Wall \
+ unit_test.c \
+ fortuna.c \
+ hash.c \
+ ../../crypto/rijndael/rijndael-api-fst.c \
+ ../../crypto/rijndael/rijndael-alg-fst.c \
+ ../../crypto/sha2/sha2.c \
+ ../../crypto/sha2/sha256c.c \
+ -o funit_test
diff --git a/sys/dev/random/dummy_rng.c b/sys/dev/random/dummy_rng.c
index 810a784..a7ca4b3 100644
--- a/sys/dev/random/dummy_rng.c
+++ b/sys/dev/random/dummy_rng.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
+ * Copyright (c) 2013 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,98 +28,92 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_random.h"
+
#include <sys/param.h>
+#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
+#include <sys/lock.h>
#include <sys/malloc.h>
-#include <sys/module.h>
#include <sys/random.h>
-#include <sys/selinfo.h>
+#include <sys/syslog.h>
#include <sys/systm.h>
-#include <sys/time.h>
-#include <dev/random/random_adaptors.h>
#include <dev/random/randomdev.h>
-
-static struct mtx dummy_random_mtx;
-
-/* Used to fake out unused random calls in random_adaptor */
-static void
-random_null_func(void)
-{
-}
+#include <dev/random/random_adaptors.h>
static int
-dummy_random_poll(int events __unused, struct thread *td __unused)
+dummy_random_zero(void)
{
return (0);
}
-static int
-dummy_random_block(int flag)
+static void
+dummy_random(void)
{
- int error = 0;
-
- mtx_lock(&dummy_random_mtx);
-
- /* Blocking logic */
- while (!error) {
- if (flag & O_NONBLOCK)
- error = EWOULDBLOCK;
- else {
- printf("random: dummy device blocking on read.\n");
- error = msleep(&dummy_random_block,
- &dummy_random_mtx,
- PUSER | PCATCH, "block", 0);
- }
- }
- mtx_unlock(&dummy_random_mtx);
-
- return (error);
}
+/* ARGSUSED */
static void
dummy_random_init(void)
{
- mtx_init(&dummy_random_mtx, "sleep mtx for dummy_random",
- NULL, MTX_DEF);
-}
-
-static void
-dummy_random_deinit(void)
-{
+#ifdef RANDOM_DEBUG
+ printf("random: %s\n", __func__);
+#endif
- mtx_destroy(&dummy_random_mtx);
+ randomdev_init_reader(dummy_random_read_phony);
}
-struct random_adaptor dummy_random = {
- .ident = "Dummy entropy device that always blocks",
- .init = dummy_random_init,
- .deinit = dummy_random_deinit,
- .block = dummy_random_block,
- .poll = dummy_random_poll,
- .read = (random_read_func_t *)random_null_func,
- .reseed = (random_reseed_func_t *)random_null_func,
- .seeded = 0, /* This device can never be seeded */
- .priority = 1, /* Bottom priority, so goes to last position */
-};
-
-static int
-dummy_random_modevent(module_t mod __unused, int type, void *unused __unused)
+/* This is used only by the internal read_random(9) call, and then only
+ * if no entropy processor is loaded.
+ *
+ * Make a token effort to provide _some_ kind of output. No warranty of
+ * the quality of this output is made, mainly because its lousy.
+ *
+ * This is only used by the internal read_random(9) call when no other
+ * adaptor is active.
+ *
+ * It has external scope due to the way things work in
+ * randomdev_[de]init_reader() that the rest of the world doesn't need to
+ * know about.
+ *
+ * Caveat Emptor.
+ */
+u_int
+dummy_random_read_phony(uint8_t *buf, u_int count)
{
+ /* If no entropy device is loaded, don't spam the console with warnings */
+ static int warned = 0;
+ u_long randval;
+ size_t size, i;
+
+ if (!warned) {
+ log(LOG_WARNING, "random device not loaded/active; using insecure pseudo-random number generator\n");
+ warned = 1;
+ }
- switch (type) {
- case MOD_LOAD:
- random_adaptor_register("dummy", &dummy_random);
- EVENTHANDLER_INVOKE(random_adaptor_attach,
- &dummy_random);
+ /* srandom() is called in kern/init_main.c:proc0_post() */
- return (0);
+ /* Fill buf[] with random(9) output */
+ for (i = 0; i < count; i += sizeof(randval)) {
+ randval = random();
+ size = MIN(count - i, sizeof(randval));
+ memcpy(buf + i, &randval, (size_t)size);
}
- return (EINVAL);
+ return (count);
}
-RANDOM_ADAPTOR_MODULE(dummy, dummy_random_modevent, 1);
+struct random_adaptor randomdev_dummy = {
+ .ra_ident = "Dummy",
+ .ra_priority = 1, /* Bottom priority, so goes to last position */
+ .ra_reseed = dummy_random,
+ .ra_seeded = (random_adaptor_seeded_func_t *)dummy_random_zero,
+ .ra_read = (random_adaptor_read_func_t *)dummy_random_zero,
+ .ra_write = (random_adaptor_write_func_t *)dummy_random_zero,
+ .ra_init = dummy_random_init,
+ .ra_deinit = dummy_random,
+};
diff --git a/sys/dev/random/fortuna.c b/sys/dev/random/fortuna.c
new file mode 100644
index 0000000..46ec88d
--- /dev/null
+++ b/sys/dev/random/fortuna.c
@@ -0,0 +1,433 @@
+/*-
+ * Copyright (c) 2013-2014 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$");
+
+#ifdef _KERNEL
+#include "opt_random.h"
+
+#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_adaptors.h>
+#include <dev/random/random_harvestq.h>
+#include <dev/random/uint128.h>
+#include <dev/random/fortuna.h>
+#else /* !_KERNEL */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <threads.h>
+
+#include "unit_test.h"
+
+#include <crypto/rijndael/rijndael-api-fst.h>
+#include <crypto/sha2/sha2.h>
+
+#include <dev/random/hash.h>
+#include <dev/random/uint128.h>
+#include <dev/random/fortuna.h>
+#endif /* _KERNEL */
+
+#if !defined(RANDOM_YARROW) && !defined(RANDOM_FORTUNA)
+#define RANDOM_YARROW
+#elif defined(RANDOM_YARROW) && defined(RANDOM_FORTUNA)
+#error "Must define either RANDOM_YARROW or RANDOM_FORTUNA"
+#endif
+
+#if defined(RANDOM_FORTUNA)
+
+#define NPOOLS 32
+#define MINPOOLSIZE 64
+#define DEFPOOLSIZE 256
+#define MAXPOOLSIZE 65536
+
+/* This algorithm (and code) presumes that KEYSIZE is twice as large as BLOCKSIZE */
+CTASSERT(BLOCKSIZE == sizeof(uint128_t));
+CTASSERT(KEYSIZE == 2*BLOCKSIZE);
+
+/* This is the beastie that needs protecting. It contains all of the
+ * state that we are excited about.
+ * Exactly one is instantiated.
+ */
+static struct fortuna_state {
+ /* P_i */
+ struct pool {
+ u_int length;
+ struct randomdev_hash hash;
+ } pool[NPOOLS];
+
+ /* ReseedCnt */
+ u_int reseedcount;
+
+ /* C - 128 bits */
+ union {
+ uint8_t byte[BLOCKSIZE];
+ uint128_t whole;
+ } counter;
+
+ /* K */
+ struct randomdev_key key;
+
+ /* Extras */
+ u_int minpoolsize;
+
+ /* Extras for the OS */
+
+#ifdef _KERNEL
+ /* For use when 'pacing' the reseeds */
+ sbintime_t lasttime;
+#endif
+} fortuna_state;
+
+/* The random_reseed_mtx mutex protects seeding and polling/blocking. */
+static mtx_t random_reseed_mtx;
+
+static struct fortuna_start_cache {
+ uint8_t junk[PAGE_SIZE];
+ size_t length;
+ struct randomdev_hash hash;
+} fortuna_start_cache;
+
+#ifdef _KERNEL
+static struct sysctl_ctx_list random_clist;
+RANDOM_CHECK_UINT(minpoolsize, MINPOOLSIZE, MAXPOOLSIZE);
+#endif
+
+void
+random_fortuna_init_alg(void)
+{
+ int i;
+#ifdef _KERNEL
+ struct sysctl_oid *random_fortuna_o;
+#endif
+
+ memset(fortuna_start_cache.junk, 0, sizeof(fortuna_start_cache.junk));
+ fortuna_start_cache.length = 0U;
+ randomdev_hash_init(&fortuna_start_cache.hash);
+
+ /* Set up a lock for the reseed process */
+#ifdef _KERNEL
+ mtx_init(&random_reseed_mtx, "reseed mutex", NULL, MTX_DEF);
+#else /* !_KERNEL */
+ mtx_init(&random_reseed_mtx, mtx_plain);
+#endif /* _KERNEL */
+
+#ifdef _KERNEL
+ /* Fortuna parameters. Do not adjust these unless you have
+ * have a very good clue about what they do!
+ */
+ random_fortuna_o = SYSCTL_ADD_NODE(&random_clist,
+ SYSCTL_STATIC_CHILDREN(_kern_random),
+ OID_AUTO, "fortuna", CTLFLAG_RW, 0,
+ "Fortuna Parameters");
+
+ SYSCTL_ADD_PROC(&random_clist,
+ SYSCTL_CHILDREN(random_fortuna_o), OID_AUTO,
+ "minpoolsize", CTLTYPE_UINT|CTLFLAG_RW,
+ &fortuna_state.minpoolsize, DEFPOOLSIZE,
+ random_check_uint_minpoolsize, "IU",
+ "Minimum pool size necessary to cause a reseed automatically");
+
+ fortuna_state.lasttime = 0U;
+#endif
+
+ fortuna_state.minpoolsize = DEFPOOLSIZE;
+
+ /* F&S - InitializePRNG() */
+
+ /* F&S - P_i = \epsilon */
+ for (i = 0; i < NPOOLS; i++) {
+ randomdev_hash_init(&fortuna_state.pool[i].hash);
+ fortuna_state.pool[i].length = 0U;
+ }
+
+ /* F&S - ReseedCNT = 0 */
+ fortuna_state.reseedcount = 0U;
+
+ /* F&S - InitializeGenerator() */
+
+ /* F&S - C = 0 */
+ uint128_clear(&fortuna_state.counter.whole);
+
+ /* F&S - K = 0 */
+ memset(&fortuna_state.key, 0, sizeof(fortuna_state.key));
+}
+
+void
+random_fortuna_deinit_alg(void)
+{
+
+ mtx_destroy(&random_reseed_mtx);
+ memset(&fortuna_state, 0, sizeof(fortuna_state));
+}
+
+/* F&S - AddRandomEvent() */
+/* Process a single stochastic event off the harvest queue */
+void
+random_fortuna_process_event(struct harvest_event *event)
+{
+ u_int pl;
+
+ /* We must be locked for all this as plenty of state gets messed with */
+ mtx_lock(&random_reseed_mtx);
+
+ /* Accumulate the event into the appropriate pool
+ * where each event carries the destination information
+ */
+ /* F&S - P_i = P_i|<harvested stuff> */
+ /* The hash_init and hash_finish are done in random_fortuna_read() below */
+ pl = event->he_destination % NPOOLS;
+ randomdev_hash_iterate(&fortuna_state.pool[pl].hash, event, sizeof(*event));
+ /* No point in counting above the outside maximum */
+ fortuna_state.pool[pl].length += event->he_size;
+ fortuna_state.pool[pl].length = MIN(fortuna_state.pool[pl].length, MAXPOOLSIZE);
+
+ /* Done with state-messing */
+ mtx_unlock(&random_reseed_mtx);
+}
+
+/* F&S - Reseed() */
+/* Reseed Mutex is held */
+static void
+reseed(uint8_t *junk, u_int length)
+{
+ struct randomdev_hash context;
+ uint8_t hash[KEYSIZE], temp[KEYSIZE];
+
+ KASSERT(fortuna_state.minpoolsize > 0, ("random: Fortuna threshold = 0"));
+#ifdef _KERNEL
+ mtx_assert(&random_reseed_mtx, MA_OWNED);
+#endif
+
+ /* F&S - temp = H(K|s) */
+ randomdev_hash_init(&context);
+ randomdev_hash_iterate(&context, &fortuna_state.key, sizeof(fortuna_state.key));
+ randomdev_hash_iterate(&context, junk, length);
+ randomdev_hash_finish(&context, temp);
+
+ /* F&S - hash = H(temp) */
+ randomdev_hash_init(&context);
+ randomdev_hash_iterate(&context, temp, KEYSIZE);
+ randomdev_hash_finish(&context, hash);
+
+ /* F&S - K = hash */
+ randomdev_encrypt_init(&fortuna_state.key, temp);
+ memset(temp, 0, sizeof(temp));
+ memset(hash, 0, sizeof(hash));
+
+ /* Unblock the device if it was blocked due to being unseeded */
+ if (uint128_is_zero(fortuna_state.counter.whole))
+ random_adaptor_unblock();
+ /* F&S - C = C + 1 */
+ uint128_increment(&fortuna_state.counter.whole);
+}
+
+/* F&S - GenerateBlocks() */
+/* Reseed Mutex is held, and buf points to a whole number of blocks. */
+static __inline void
+random_fortuna_genblocks(uint8_t *buf, u_int blockcount)
+{
+ u_int i;
+
+ for (i = 0u; i < blockcount; i++) {
+ /* F&S - r = r|E(K,C) */
+ randomdev_encrypt(&fortuna_state.key, fortuna_state.counter.byte, buf, BLOCKSIZE);
+ buf += BLOCKSIZE;
+
+ /* F&S - C = C + 1 */
+ uint128_increment(&fortuna_state.counter.whole);
+ }
+}
+
+/* F&S - PseudoRandomData() */
+/* Reseed Mutex is held, and buf points to a whole number of blocks. */
+static __inline void
+random_fortuna_genrandom(uint8_t *buf, u_int bytecount)
+{
+ static uint8_t temp[BLOCKSIZE*(KEYSIZE/BLOCKSIZE)];
+ u_int blockcount;
+
+ /* F&S - assert(n < 2^20) */
+ KASSERT((bytecount <= (1 << 20)), ("invalid single read request to fortuna of %d bytes", bytecount));
+
+ /* F&S - r = first-n-bytes(GenerateBlocks(ceil(n/16))) */
+ blockcount = (bytecount + BLOCKSIZE - 1)/BLOCKSIZE;
+ random_fortuna_genblocks(buf, blockcount);
+
+ /* F&S - K = GenerateBlocks(2) */
+ random_fortuna_genblocks(temp, KEYSIZE/BLOCKSIZE);
+ randomdev_encrypt_init(&fortuna_state.key, temp);
+ memset(temp, 0, sizeof(temp));
+}
+
+/* F&S - RandomData() */
+/* Used to return processed entropy from the PRNG */
+/* The argument buf points to a whole number of blocks. */
+void
+random_fortuna_read(uint8_t *buf, u_int bytecount)
+{
+#ifdef _KERNEL
+ sbintime_t thistime;
+#endif
+ struct randomdev_hash context;
+ uint8_t s[NPOOLS*KEYSIZE], temp[KEYSIZE];
+ int i;
+ u_int seedlength;
+
+ /* We must be locked for all this as plenty of state gets messed with */
+ mtx_lock(&random_reseed_mtx);
+
+ /* if buf == NULL and bytecount == 0 then this is the pre-read. */
+ /* if buf == NULL and bytecount != 0 then this is the post-read; ignore. */
+ if (buf == NULL) {
+ if (bytecount == 0) {
+ if (fortuna_state.pool[0].length >= fortuna_state.minpoolsize
+#ifdef _KERNEL
+ /* F&S - Use 'getsbinuptime()' to prevent reseed-spamming. */
+ && ((thistime = getsbinuptime()) - fortuna_state.lasttime > hz/10)
+#endif
+ ) {
+#ifdef _KERNEL
+ fortuna_state.lasttime = thistime;
+#endif
+
+ seedlength = 0U;
+ /* F&S - ReseedCNT = ReseedCNT + 1 */
+ fortuna_state.reseedcount++;
+ /* s = \epsilon by default */
+ for (i = 0; i < NPOOLS; i++) {
+ /* F&S - if Divides(ReseedCnt, 2^i) ... */
+ if ((fortuna_state.reseedcount % (1 << i)) == 0U) {
+ seedlength += KEYSIZE;
+ /* F&S - temp = (P_i) */
+ randomdev_hash_finish(&fortuna_state.pool[i].hash, temp);
+ /* F&S - P_i = \epsilon */
+ randomdev_hash_init(&fortuna_state.pool[i].hash);
+ fortuna_state.pool[i].length = 0U;
+ /* F&S - s = s|H(temp) */
+ randomdev_hash_init(&context);
+ randomdev_hash_iterate(&context, temp, KEYSIZE);
+ randomdev_hash_finish(&context, s + i*KEYSIZE);
+ }
+ else
+ break;
+ }
+#ifdef RANDOM_DEBUG
+ printf("random: active reseed: reseedcount [%d] ", fortuna_state.reseedcount);
+ for (i = 0; i < NPOOLS; i++)
+ printf(" %d", fortuna_state.pool[i].length);
+ printf("\n");
+#endif
+ /* F&S */
+ reseed(s, seedlength);
+
+ /* Clean up */
+ memset(s, 0, seedlength);
+ seedlength = 0U;
+ memset(temp, 0, sizeof(temp));
+ memset(&context, 0, sizeof(context));
+ }
+ }
+ }
+ /* if buf != NULL do a regular read. */
+ else
+ random_fortuna_genrandom(buf, bytecount);
+
+ mtx_unlock(&random_reseed_mtx);
+}
+
+/* Internal function to hand external entropy to the PRNG */
+void
+random_fortuna_write(uint8_t *buf, u_int count)
+{
+ uint8_t temp[KEYSIZE];
+ int i;
+ uintmax_t timestamp;
+
+ timestamp = get_cyclecount();
+ randomdev_hash_iterate(&fortuna_start_cache.hash, &timestamp, sizeof(timestamp));
+ randomdev_hash_iterate(&fortuna_start_cache.hash, buf, count);
+ timestamp = get_cyclecount();
+ randomdev_hash_iterate(&fortuna_start_cache.hash, &timestamp, sizeof(timestamp));
+ randomdev_hash_finish(&fortuna_start_cache.hash, temp);
+ for (i = 0; i < KEYSIZE; i++)
+ fortuna_start_cache.junk[(fortuna_start_cache.length + i)%PAGE_SIZE] ^= temp[i];
+ fortuna_start_cache.length += KEYSIZE;
+
+#ifdef RANDOM_DEBUG
+ printf("random: %s - ", __func__);
+ for (i = 0; i < KEYSIZE; i++)
+ printf("%02X", temp[i]);
+ printf("\n");
+#endif
+
+ memset(temp, 0, KEYSIZE);
+
+ /* We must be locked for all this as plenty of state gets messed with */
+ mtx_lock(&random_reseed_mtx);
+
+ randomdev_hash_init(&fortuna_start_cache.hash);
+
+ reseed(fortuna_start_cache.junk, MIN(PAGE_SIZE, fortuna_start_cache.length));
+ memset(fortuna_start_cache.junk, 0, sizeof(fortuna_start_cache.junk));
+
+ mtx_unlock(&random_reseed_mtx);
+}
+
+void
+random_fortuna_reseed(void)
+{
+
+ /* CWOT */
+}
+
+int
+random_fortuna_seeded(void)
+{
+
+ return (!uint128_is_zero(fortuna_state.counter.whole));
+}
+
+#endif /* RANDOM_FORTUNA */
diff --git a/sys/dev/random/rwfile.h b/sys/dev/random/fortuna.h
index f14fd7b..81fcac3 100644
--- a/sys/dev/random/rwfile.h
+++ b/sys/dev/random/fortuna.h
@@ -26,14 +26,19 @@
* $FreeBSD$
*/
-#ifndef SYS_DEV_RANDOM_RWFILE_H_INCLUDED
-#define SYS_DEV_RANDOM_RWFILE_H_INCLUDED
-
-#ifdef RANDOM_RWFILE
-
-int randomdev_read_file(const char *filename, void *buf, size_t);
-int randomdev_write_file(const char *filename, void *buf, size_t);
+#ifndef SYS_DEV_RANDOM_FORTUNA_H_INCLUDED
+#define SYS_DEV_RANDOM_FORTUNA_H_INCLUDED
+#ifdef _KERNEL
+typedef struct mtx mtx_t;
#endif
+void random_fortuna_init_alg(void);
+void random_fortuna_deinit_alg(void);
+void random_fortuna_read(uint8_t *, u_int);
+void random_fortuna_write(uint8_t *, u_int);
+void random_fortuna_reseed(void);
+int random_fortuna_seeded(void);
+void random_fortuna_process_event(struct harvest_event *event);
+
#endif
diff --git a/sys/dev/random/harvest.c b/sys/dev/random/harvest.c
deleted file mode 100644
index 9dbae84..0000000
--- a/sys/dev/random/harvest.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*-
- * Copyright (c) 2000-2013 Mark R V Murray
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer
- * in this position and unchanged.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/kthread.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/mutex.h>
-#include <sys/poll.h>
-#include <sys/queue.h>
-#include <sys/random.h>
-#include <sys/selinfo.h>
-#include <sys/syslog.h>
-#include <sys/systm.h>
-#include <sys/sysctl.h>
-
-#include <machine/cpu.h>
-
-#include <dev/random/randomdev_soft.h>
-
-static int read_random_phony(void *, int);
-
-/* Structure holding the desired entropy sources */
-struct harvest_select harvest = { 1, 1, 1, 1 };
-static int warned = 0;
-
-/* hold the address of the routine which is actually called if
- * the randomdev is loaded
- */
-static void (*reap_func)(u_int64_t, const void *, u_int, u_int,
- enum esource) = NULL;
-static int (*read_func)(void *, int) = read_random_phony;
-
-/* Initialise the harvester at load time */
-void
-randomdev_init_harvester(void (*reaper)(u_int64_t, const void *, u_int,
- u_int, enum esource), int (*reader)(void *, int))
-{
- reap_func = reaper;
- read_func = reader;
-}
-
-/* Deinitialise the harvester at unload time */
-void
-randomdev_deinit_harvester(void)
-{
- reap_func = NULL;
- read_func = read_random_phony;
- warned = 0;
-}
-
-/* Entropy harvesting routine. This is supposed to be fast; do
- * not do anything slow in here!
- * Implemented as in indirect call to allow non-inclusion of
- * the entropy device.
- *
- * XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle
- * counters are built in, but on older hardware it will do a real time clock
- * read which can be quite expensive.
- */
-void
-random_harvest(const void *entropy, u_int count, u_int bits, enum esource origin)
-{
- if (reap_func)
- (*reap_func)(get_cyclecount(), entropy, count, bits, origin);
-}
-
-/* Userland-visible version of read_random */
-int
-read_random(void *buf, int count)
-{
- return ((*read_func)(buf, count));
-}
-
-/* If the entropy device is not loaded, make a token effort to
- * provide _some_ kind of randomness. This should only be used
- * inside other RNG's, like arc4random(9).
- */
-static int
-read_random_phony(void *buf, int count)
-{
- u_long randval;
- int size, i;
-
- if (!warned) {
- log(LOG_WARNING, "random device not loaded; using insecure entropy\n");
- warned = 1;
- }
-
- /* srandom() is called in kern/init_main.c:proc0_post() */
-
- /* Fill buf[] with random(9) output */
- for (i = 0; i < count; i+= (int)sizeof(u_long)) {
- randval = random();
- size = MIN(count - i, sizeof(u_long));
- memcpy(&((char *)buf)[i], &randval, (size_t)size);
- }
-
- return (count);
-}
-
-/* Helper routine to enable kproc_exit() to work while the module is
- * being (or has been) unloaded.
- * This routine is in this file because it is always linked into the kernel,
- * and will thus never be unloaded. This is critical for unloadable modules
- * that have threads.
- */
-void
-random_set_wakeup_exit(void *control)
-{
- wakeup(control);
- kproc_exit(0);
- /* NOTREACHED */
-}
diff --git a/sys/dev/random/hash.c b/sys/dev/random/hash.c
index cf0feaa..7deee87 100644
--- a/sys/dev/random/hash.c
+++ b/sys/dev/random/hash.c
@@ -28,18 +28,33 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#ifdef _KERNEL
#include <sys/param.h>
#include <sys/systm.h>
+#else /* !_KERNEL */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <threads.h>
+#include "unit_test.h"
+#endif /* _KERNEL */
#include <crypto/rijndael/rijndael-api-fst.h>
#include <crypto/sha2/sha2.h>
#include <dev/random/hash.h>
+/* This code presumes that KEYSIZE is twice as large as BLOCKSIZE */
+CTASSERT(KEYSIZE == 2*BLOCKSIZE);
+
/* Initialise the hash */
void
randomdev_hash_init(struct randomdev_hash *context)
{
+
SHA256_Init(&context->sha);
}
@@ -47,6 +62,7 @@ randomdev_hash_init(struct randomdev_hash *context)
void
randomdev_hash_iterate(struct randomdev_hash *context, void *data, size_t size)
{
+
SHA256_Update(&context->sha, data, size);
}
@@ -56,6 +72,7 @@ randomdev_hash_iterate(struct randomdev_hash *context, void *data, size_t size)
void
randomdev_hash_finish(struct randomdev_hash *context, void *buf)
{
+
SHA256_Final(buf, &context->sha);
}
@@ -66,6 +83,7 @@ randomdev_hash_finish(struct randomdev_hash *context, void *buf)
void
randomdev_encrypt_init(struct randomdev_key *context, void *data)
{
+
rijndael_cipherInit(&context->cipher, MODE_CBC, NULL);
rijndael_makeKey(&context->key, DIR_ENCRYPT, KEYSIZE*8, data);
}
@@ -75,7 +93,8 @@ randomdev_encrypt_init(struct randomdev_key *context, void *data)
* a multiple of BLOCKSIZE.
*/
void
-randomdev_encrypt(struct randomdev_key *context, void *d_in, void *d_out, unsigned length)
+randomdev_encrypt(struct randomdev_key *context, void *d_in, void *d_out, u_int length)
{
+
rijndael_blockEncrypt(&context->cipher, &context->key, d_in, length*8, d_out);
}
diff --git a/sys/dev/random/hash.h b/sys/dev/random/hash.h
index 4e6a4a0..57c0c6d 100644
--- a/sys/dev/random/hash.h
+++ b/sys/dev/random/hash.h
@@ -45,6 +45,6 @@ void randomdev_hash_init(struct randomdev_hash *);
void randomdev_hash_iterate(struct randomdev_hash *, void *, size_t);
void randomdev_hash_finish(struct randomdev_hash *, void *);
void randomdev_encrypt_init(struct randomdev_key *, void *);
-void randomdev_encrypt(struct randomdev_key *context, void *, void *, unsigned);
+void randomdev_encrypt(struct randomdev_key *context, void *, void *, u_int);
#endif
diff --git a/sys/dev/random/ivy.c b/sys/dev/random/ivy.c
index 23fd542..724e7aa 100644
--- a/sys/dev/random/ivy.c
+++ b/sys/dev/random/ivy.c
@@ -35,11 +35,11 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
+#include <sys/conf.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/random.h>
-#include <sys/selinfo.h>
#include <sys/systm.h>
#include <machine/md_var.h>
@@ -47,18 +47,17 @@ __FBSDID("$FreeBSD$");
#include <dev/random/randomdev.h>
#include <dev/random/randomdev_soft.h>
-#include <dev/random/random_harvestq.h>
-#include <dev/random/live_entropy_sources.h>
#include <dev/random/random_adaptors.h>
+#include <dev/random/live_entropy_sources.h>
#define RETRY_COUNT 10
-static int random_ivy_read(void *, int);
+static u_int random_ivy_read(void *, u_int);
-static struct random_hardware_source random_ivy = {
- .ident = "Hardware, Intel Secure Key RNG",
- .source = RANDOM_PURE_RDRAND,
- .read = random_ivy_read
+static struct live_entropy_source random_ivy = {
+ .les_ident = "Intel Secure Key RNG",
+ .les_source = RANDOM_PURE_RDRAND,
+ .les_read = random_ivy_read
};
static inline int
@@ -86,15 +85,17 @@ ivy_rng_store(long *buf)
#endif
}
-static int
-random_ivy_read(void *buf, int c)
+/* It is specifically allowed that buf is a multiple of sizeof(long) */
+static u_int
+random_ivy_read(void *buf, u_int c)
{
long *b;
- int count;
+ u_int count;
- KASSERT(c % sizeof(long) == 0, ("partial read %d", c));
- for (b = buf, count = c; count > 0; count -= sizeof(long), b++) {
- if (ivy_rng_store(b) == 0)
+ KASSERT(c % sizeof(*b) == 0, ("partial read %d", c));
+ b = buf;
+ for (count = c; count > 0; count -= sizeof(*b)) {
+ if (ivy_rng_store(b++) == 0)
break;
}
return (c - count);
@@ -107,14 +108,10 @@ rdrand_modevent(module_t mod, int type, void *unused)
switch (type) {
case MOD_LOAD:
- if (cpu_feature2 & CPUID2_RDRAND)
+ if (cpu_feature2 & CPUID2_RDRAND) {
live_entropy_source_register(&random_ivy);
- else
-#ifndef KLD_MODULE
- if (bootverbose)
-#endif
- printf("%s: RDRAND is not present\n",
- random_ivy.ident);
+ printf("random: live provider: \"%s\"\n", random_ivy.les_ident);
+ }
break;
case MOD_UNLOAD:
@@ -134,4 +131,6 @@ rdrand_modevent(module_t mod, int type, void *unused)
return (error);
}
-LIVE_ENTROPY_SRC_MODULE(random_rdrand, rdrand_modevent, 1);
+DEV_MODULE(rdrand, rdrand_modevent, NULL);
+MODULE_VERSION(rdrand, 1);
+MODULE_DEPEND(rdrand, random_adaptors, 1, 1, 1);
diff --git a/sys/dev/random/live_entropy_sources.c b/sys/dev/random/live_entropy_sources.c
index d406ebd..9899cb4 100644
--- a/sys/dev/random/live_entropy_sources.c
+++ b/sys/dev/random/live_entropy_sources.c
@@ -28,13 +28,16 @@
#include <sys/param.h>
__FBSDID("$FreeBSD$");
+#include "opt_random.h"
+
#include <sys/kernel.h>
#include <sys/libkern.h>
#include <sys/lock.h>
#include <sys/malloc.h>
+#include <sys/module.h>
#include <sys/queue.h>
#include <sys/random.h>
-#include <sys/selinfo.h>
+#include <sys/sbuf.h>
#include <sys/sx.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
@@ -49,89 +52,73 @@ __FBSDID("$FreeBSD$");
#include "live_entropy_sources.h"
-LIST_HEAD(les_head, live_entropy_sources);
-static struct les_head sources = LIST_HEAD_INITIALIZER(sources);
-
/*
- * The live_lock protects the consistency of the "struct les_head sources"
+ * The les_lock protects the consistency of the "struct les_head les_sources"
*/
-static struct sx les_lock; /* need a sleepable lock */
+static struct sx les_lock; /* Need a sleepable lock for the sbuf/sysctl stuff. */
+
+LIST_HEAD(les_head, live_entropy_sources);
+static struct les_head les_sources = LIST_HEAD_INITIALIZER(les_sources);
void
-live_entropy_source_register(struct random_hardware_source *rsource)
+live_entropy_source_register(struct live_entropy_source *rsource)
{
- struct live_entropy_sources *les;
+ struct live_entropy_sources *lles;
KASSERT(rsource != NULL, ("invalid input to %s", __func__));
- les = malloc(sizeof(struct live_entropy_sources), M_ENTROPY, M_WAITOK);
- les->rsource = rsource;
+ lles = malloc(sizeof(*lles), M_ENTROPY, M_WAITOK);
+ lles->lles_rsource = rsource;
sx_xlock(&les_lock);
- LIST_INSERT_HEAD(&sources, les, entries);
+ LIST_INSERT_HEAD(&les_sources, lles, lles_entries);
sx_xunlock(&les_lock);
}
void
-live_entropy_source_deregister(struct random_hardware_source *rsource)
+live_entropy_source_deregister(struct live_entropy_source *rsource)
{
- struct live_entropy_sources *les = NULL;
+ struct live_entropy_sources *lles = NULL;
KASSERT(rsource != NULL, ("invalid input to %s", __func__));
sx_xlock(&les_lock);
- LIST_FOREACH(les, &sources, entries)
- if (les->rsource == rsource) {
- LIST_REMOVE(les, entries);
+ LIST_FOREACH(lles, &les_sources, lles_entries)
+ if (lles->lles_rsource == rsource) {
+ LIST_REMOVE(lles, lles_entries);
break;
}
sx_xunlock(&les_lock);
- if (les != NULL)
- free(les, M_ENTROPY);
+ if (lles != NULL)
+ free(lles, M_ENTROPY);
}
static int
live_entropy_source_handler(SYSCTL_HANDLER_ARGS)
{
- struct live_entropy_sources *les;
+ struct live_entropy_sources *lles;
+ struct sbuf sbuf;
int error, count;
- count = error = 0;
-
sx_slock(&les_lock);
- if (LIST_EMPTY(&sources))
- error = SYSCTL_OUT(req, "", 0);
- else {
- LIST_FOREACH(les, &sources, entries) {
-
- error = SYSCTL_OUT(req, ",", count++ ? 1 : 0);
- if (error)
- break;
+ sbuf_new_for_sysctl(&sbuf, NULL, 64, req);
- error = SYSCTL_OUT(req, les->rsource->ident, strlen(les->rsource->ident));
- if (error)
- break;
- }
+ count = 0;
+ LIST_FOREACH(lles, &les_sources, lles_entries) {
+ sbuf_cat(&sbuf, (count++ ? ",'" : "'"));
+ sbuf_cat(&sbuf, lles->lles_rsource->les_ident);
+ sbuf_cat(&sbuf, "'");
}
+ error = sbuf_finish(&sbuf);
+ sbuf_delete(&sbuf);
+
sx_sunlock(&les_lock);
return (error);
}
-static void
-live_entropy_sources_init(void *unused)
-{
-
- SYSCTL_PROC(_kern_random, OID_AUTO, live_entropy_sources,
- CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
- NULL, 0, live_entropy_source_handler, "",
- "List of Active Live Entropy Sources");
-
- sx_init(&les_lock, "live_entropy_sources");
-}
-
/*
* Run through all "live" sources reading entropy for the given
* number of rounds, which should be a multiple of the number
@@ -140,15 +127,18 @@ live_entropy_sources_init(void *unused)
*
* BEWARE!!!
* This function runs inside the RNG thread! Don't do anything silly!
- * Remember that we are NOT holding harvest_mtx on entry!
+ */
+/* XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle
+ * counters are built in, but on older hardware it will do a real time clock
+ * read which can be quite expensive.
*/
void
-live_entropy_sources_feed(int rounds, event_proc_f entropy_processor)
+live_entropy_sources_feed(void)
{
- static struct harvest event;
- static uint8_t buf[HARVESTSIZE];
- struct live_entropy_sources *les;
- int i, n;
+ static struct harvest_event event;
+ struct live_entropy_sources *lles;
+ int i, read_rate;
+ u_int n;
sx_slock(&les_lock);
@@ -156,25 +146,23 @@ live_entropy_sources_feed(int rounds, event_proc_f entropy_processor)
* Walk over all of live entropy sources, and feed their output
* to the system-wide RNG.
*/
- LIST_FOREACH(les, &sources, entries) {
-
- for (i = 0; i < rounds; i++) {
- /*
- * This should be quick, since it's a live entropy
- * source.
- */
- /* FIXME: Whine loudly if this didn't work. */
- n = les->rsource->read(buf, sizeof(buf));
- n = MIN(n, HARVESTSIZE);
-
- event.somecounter = get_cyclecount();
- event.size = n;
- event.bits = (n*8)/2;
- event.source = les->rsource->source;
- memcpy(event.entropy, buf, n);
+ read_rate = random_adaptor_read_rate();
+ LIST_FOREACH(lles, &les_sources, lles_entries) {
+
+ for (i = 0; i < harvest_pool_count*read_rate; i++) {
+ /* This *must* be quick, since it's a live entropy source. */
+ n = lles->lles_rsource->les_read(event.he_entropy, HARVESTSIZE);
+ KASSERT((n > 0 && n <= HARVESTSIZE), ("very bad return from les_read (= %d) in %s", n, __func__));
+ memset(event.he_entropy + n, 0, HARVESTSIZE - n);
+
+ event.he_somecounter = get_cyclecount();
+ event.he_size = n;
+ event.he_bits = (n*8)/2;
+ event.he_source = lles->lles_rsource->les_source;
+ event.he_destination = harvest_destination[event.he_source]++;
/* Do the actual entropy insertion */
- entropy_processor(&event);
+ harvest_process_event(&event);
}
}
@@ -182,14 +170,21 @@ live_entropy_sources_feed(int rounds, event_proc_f entropy_processor)
sx_sunlock(&les_lock);
}
-static void
-live_entropy_sources_deinit(void *unused)
+void
+live_entropy_sources_init(void)
{
- sx_destroy(&les_lock);
+ SYSCTL_PROC(_kern_random, OID_AUTO, live_entropy_sources,
+ CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ NULL, 0, live_entropy_source_handler, "",
+ "List of Active Live Entropy Sources");
+
+ sx_init(&les_lock, "live_entropy_sources");
}
-SYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST,
- live_entropy_sources_init, NULL);
-SYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST,
- live_entropy_sources_deinit, NULL);
+void
+live_entropy_sources_deinit(void)
+{
+
+ sx_destroy(&les_lock);
+}
diff --git a/sys/dev/random/live_entropy_sources.h b/sys/dev/random/live_entropy_sources.h
index 9a23070..95e2e4b 100644
--- a/sys/dev/random/live_entropy_sources.h
+++ b/sys/dev/random/live_entropy_sources.h
@@ -30,31 +30,30 @@
#ifndef SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED
#define SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED
+typedef u_int random_live_read_func_t(void *, u_int);
+
/*
* Live entropy source is a source of entropy that can provide
* specified or approximate amount of entropy immediately upon request or within
* an acceptable amount of time.
*/
+struct live_entropy_source {
+ const char *les_ident;
+ enum random_entropy_source les_source;
+ random_live_read_func_t *les_read;
+};
+
struct live_entropy_sources {
- LIST_ENTRY(live_entropy_sources) entries; /* list of providers */
- struct random_hardware_source *rsource; /* associated random adaptor */
+ LIST_ENTRY(live_entropy_sources) lles_entries; /* list of providers */
+ struct live_entropy_source *lles_rsource; /* associated random adaptor */
};
extern struct mtx live_mtx;
-void live_entropy_source_register(struct random_hardware_source *);
-void live_entropy_source_deregister(struct random_hardware_source *);
-void live_entropy_sources_feed(int, event_proc_f);
-
-#define LIVE_ENTROPY_SRC_MODULE(name, modevent, ver) \
- static moduledata_t name##_mod = { \
- #name, \
- modevent, \
- 0 \
- }; \
- DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, \
- SI_ORDER_SECOND); \
- MODULE_VERSION(name, ver); \
- MODULE_DEPEND(name, random, 1, 1, 1);
+void live_entropy_sources_init(void);
+void live_entropy_sources_deinit(void);
+void live_entropy_source_register(struct live_entropy_source *);
+void live_entropy_source_deregister(struct live_entropy_source *);
+void live_entropy_sources_feed(void);
#endif /* SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED */
diff --git a/sys/dev/random/nehemiah.c b/sys/dev/random/nehemiah.c
index b60689e..4740250 100644
--- a/sys/dev/random/nehemiah.c
+++ b/sys/dev/random/nehemiah.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2013 Mark R V Murray
+ * Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,11 +31,11 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
+#include <sys/conf.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/random.h>
-#include <sys/selinfo.h>
#include <sys/systm.h>
#include <machine/segments.h>
@@ -44,21 +45,20 @@ __FBSDID("$FreeBSD$");
#include <dev/random/randomdev.h>
#include <dev/random/randomdev_soft.h>
-#include <dev/random/random_harvestq.h>
-#include <dev/random/live_entropy_sources.h>
#include <dev/random/random_adaptors.h>
+#include <dev/random/live_entropy_sources.h>
static void random_nehemiah_init(void);
static void random_nehemiah_deinit(void);
-static int random_nehemiah_read(void *, int);
+static u_int random_nehemiah_read(void *, u_int);
-static struct random_hardware_source random_nehemiah = {
- .ident = "Hardware, VIA Nehemiah Padlock RNG",
- .source = RANDOM_PURE_NEHEMIAH,
- .read = random_nehemiah_read
+static struct live_entropy_source random_nehemiah = {
+ .les_ident = "VIA Nehemiah Padlock RNG",
+ .les_source = RANDOM_PURE_NEHEMIAH,
+ .les_read = random_nehemiah_read
};
-/* TODO: now that the Davies-Meyer hash is gone and we only use
+/* XXX: FIX? Now that the Davies-Meyer hash is gone and we only use
* the 'xstore' instruction, do we still need to preserve the
* FPU state with fpu_kern_(enter|leave)() ?
*/
@@ -75,7 +75,7 @@ VIA_RNG_store(void *buf)
#ifdef __GNUCLIKE_ASM
__asm __volatile(
"movl $0,%%edx\n\t"
- ".byte 0x0f, 0xa7, 0xc0" /* xstore */
+ "xstore"
: "=a" (retval), "+d" (rate), "+D" (buf)
:
: "memory"
@@ -100,8 +100,9 @@ random_nehemiah_deinit(void)
fpu_kern_free_ctx(fpu_ctx_save);
}
-static int
-random_nehemiah_read(void *buf, int c)
+/* It is specifically allowed that buf is a multiple of sizeof(long) */
+static u_int
+random_nehemiah_read(void *buf, u_int c)
{
uint8_t *b;
size_t count, ret;
@@ -131,13 +132,9 @@ nehemiah_modevent(module_t mod, int type, void *unused)
case MOD_LOAD:
if (via_feature_rng & VIA_HAS_RNG) {
live_entropy_source_register(&random_nehemiah);
+ printf("random: live provider: \"%s\"\n", random_nehemiah.les_ident);
random_nehemiah_init();
- } else
-#ifndef KLD_MODULE
- if (bootverbose)
-#endif
- printf("%s: VIA Padlock RNG not present\n",
- random_nehemiah.ident);
+ }
break;
case MOD_UNLOAD:
@@ -158,4 +155,6 @@ nehemiah_modevent(module_t mod, int type, void *unused)
return (error);
}
-LIVE_ENTROPY_SRC_MODULE(nehemiah, nehemiah_modevent, 1);
+DEV_MODULE(nehemiah, nehemiah_modevent, NULL);
+MODULE_VERSION(nehemiah, 1);
+MODULE_DEPEND(nehemiah, random_adaptors, 1, 1, 1);
diff --git a/sys/dev/random/random_adaptors.c b/sys/dev/random/random_adaptors.c
index aa6db7b..c58f929 100644
--- a/sys/dev/random/random_adaptors.c
+++ b/sys/dev/random/random_adaptors.c
@@ -1,7 +1,7 @@
/*-
+ * Copyright (c) 2013 Mark R V Murray
* Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
* Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org>
- * Copyright (c) 2013 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,195 +29,383 @@
#include <sys/param.h>
__FBSDID("$FreeBSD$");
+#include "opt_random.h"
+
#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/libkern.h>
#include <sys/lock.h>
#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/poll.h>
#include <sys/queue.h>
#include <sys/random.h>
+#include <sys/sbuf.h>
#include <sys/selinfo.h>
#include <sys/sx.h>
#include <sys/sysctl.h>
+#include <sys/uio.h>
#include <sys/unistd.h>
#include <dev/random/randomdev.h>
-#include <dev/random/randomdev_soft.h>
#include <dev/random/random_adaptors.h>
+#include <dev/random/live_entropy_sources.h>
+/* The random_adaptors_lock protects random_adaptors_list and friends and random_adaptor.
+ * We need a sleepable lock for uiomove/block/poll/sbuf/sysctl.
+ */
+static struct sx random_adaptors_lock;
LIST_HEAD(adaptors_head, random_adaptors);
-static struct adaptors_head adaptors = LIST_HEAD_INITIALIZER(adaptors);
-static struct sx adaptors_lock; /* need a sleepable lock */
-
-/* List for the dynamic sysctls */
-static struct sysctl_ctx_list random_clist;
+static struct adaptors_head random_adaptors_list = LIST_HEAD_INITIALIZER(random_adaptors_list);
+static struct random_adaptor *random_adaptor = NULL; /* Currently active adaptor */
+/* End of data items requiring random_adaptors_lock protection */
-struct random_adaptor *random_adaptor;
+/* The random_readrate_mtx mutex protects the read-rate estimator.
+ */
+static struct mtx random_read_rate_mtx;
+static int random_adaptor_read_rate_cache;
+/* End of data items requiring random_readrate_mtx mutex protection */
-MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures");
+static struct selinfo rsel;
-int
-random_adaptor_register(const char *name, struct random_adaptor *rsp)
+/* Utility routine to change active adaptor when the random_adaptors_list
+ * gets modified.
+ *
+ * Walk a list of registered random(4) adaptors and pick either a requested
+ * one or the highest priority one, whichever comes first. Panic on failure
+ * as the fallback must always be the "dummy" adaptor.
+ */
+static void
+random_adaptor_choose(void)
{
- struct random_adaptors *rpp;
+ char rngs[128], *token, *cp;
+ struct random_adaptors *rra, *rrai;
+ struct random_adaptor *random_adaptor_previous;
+ int primax;
- KASSERT(name != NULL && rsp != NULL, ("invalid input to %s", __func__));
+ /* We are going to be messing with random_adaptor.
+ * Exclusive lock is mandatory.
+ */
+ sx_assert(&random_adaptors_lock, SA_XLOCKED);
- rpp = malloc(sizeof(struct random_adaptors), M_ENTROPY, M_WAITOK);
- rpp->name = name;
- rpp->rsp = rsp;
+ random_adaptor_previous = random_adaptor;
- sx_xlock(&adaptors_lock);
- LIST_INSERT_HEAD(&adaptors, rpp, entries);
- sx_xunlock(&adaptors_lock);
+ random_adaptor = NULL;
+ if (TUNABLE_STR_FETCH("kern.random.active_adaptor", rngs, sizeof(rngs))) {
+ cp = rngs;
- return (0);
+ /* XXX: FIX!! (DES):
+ * - fetch tunable once, at boot
+ * - make sysctl r/w
+ * - when fetching tunable or processing a sysctl
+ * write, parse into list of strings so we don't
+ * have to do it here again and again
+ * - sysctl read should return a reconstructed string
+ */
+ while ((token = strsep(&cp, ",")) != NULL) {
+ LIST_FOREACH(rra, &random_adaptors_list, rra_entries)
+ if (strcmp(rra->rra_name, token) == 0) {
+ random_adaptor = rra->rra_ra;
+ break;
+ }
+ if (random_adaptor != NULL) {
+ printf("random: selecting requested adaptor <%s>\n",
+ random_adaptor->ra_ident);
+ break;
+ }
+ else
+ printf("random: requested adaptor <%s> not available\n",
+ token);
+ }
+ }
+
+ primax = 0;
+ if (random_adaptor == NULL) {
+ /*
+ * Fall back to the highest priority item on the available
+ * RNG list.
+ */
+ LIST_FOREACH(rrai, &random_adaptors_list, rra_entries) {
+ if (rrai->rra_ra->ra_priority >= primax) {
+ random_adaptor = rrai->rra_ra;
+ primax = rrai->rra_ra->ra_priority;
+ }
+ }
+ if (random_adaptor != NULL)
+ printf("random: selecting highest priority adaptor <%s>\n",
+ random_adaptor->ra_ident);
+ }
+
+ KASSERT(random_adaptor != NULL, ("adaptor not found"));
+
+ /* If we are changing adaptors, deinit the old and init the new. */
+ if (random_adaptor != random_adaptor_previous) {
+#ifdef RANDOM_DEBUG
+ printf("random: %s - changing from %s to %s\n", __func__,
+ (random_adaptor_previous == NULL ? "NULL" : random_adaptor_previous->ra_ident),
+ random_adaptor->ra_ident);
+#endif
+ if (random_adaptor_previous != NULL)
+ (random_adaptor_previous->ra_deinit)();
+ (random_adaptor->ra_init)();
+ }
}
-struct random_adaptor *
-random_adaptor_get(const char *name)
-{
- struct random_adaptors *rpp;
- struct random_adaptor *rsp;
- rsp = NULL;
+/* XXX: FIX!! Make sure we are not inserting a duplicate */
+void
+random_adaptor_register(const char *name, struct random_adaptor *ra)
+{
+ struct random_adaptors *rra;
- sx_slock(&adaptors_lock);
+ KASSERT(name != NULL && ra != NULL, ("invalid input to %s", __func__));
- LIST_FOREACH(rpp, &adaptors, entries)
- if (strcmp(rpp->name, name) == 0)
- rsp = rpp->rsp;
+ rra = malloc(sizeof(*rra), M_ENTROPY, M_WAITOK);
+ rra->rra_name = name;
+ rra->rra_ra = ra;
- sx_sunlock(&adaptors_lock);
+ sx_xlock(&random_adaptors_lock);
+ LIST_INSERT_HEAD(&random_adaptors_list, rra, rra_entries);
+ random_adaptor_choose();
+ sx_xunlock(&random_adaptors_lock);
- return (rsp);
+ KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
}
-/*
- * Walk a list of registered random(4) adaptors and pick the last non-selected
- * one.
- *
- * If none are selected, use yarrow if available.
- */
void
-random_adaptor_choose(struct random_adaptor **adaptor)
+random_adaptor_deregister(const char *name)
{
- char rngs[128], *token, *cp;
- struct random_adaptors *rppi, *ramax;
- unsigned primax;
+ struct random_adaptors *rra;
- KASSERT(adaptor != NULL, ("pre-conditions failed"));
+ KASSERT(name != NULL, ("invalid input to %s", __func__));
+ KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
- *adaptor = NULL;
- if (TUNABLE_STR_FETCH("kern.random.active_adaptor", rngs, sizeof(rngs))) {
- cp = rngs;
+ sx_xlock(&random_adaptors_lock);
+ LIST_FOREACH(rra, &random_adaptors_list, rra_entries)
+ if (strcmp(rra->rra_name, name) == 0) {
+ LIST_REMOVE(rra, rra_entries);
+ break;
+ }
+ random_adaptor_choose();
+ sx_xunlock(&random_adaptors_lock);
- while ((token = strsep(&cp, ",")) != NULL)
- if ((*adaptor = random_adaptor_get(token)) != NULL)
- break;
- else if (bootverbose)
- printf("%s random adaptor is not available,"
- " skipping\n", token);
+ free(rra, M_ENTROPY);
+}
+
+/* ARGSUSED */
+int
+random_adaptor_read(struct cdev *dev __unused, struct uio *uio, int flags)
+{
+ void *random_buf;
+ int c, error;
+ ssize_t nbytes;
+
+#ifdef RANDOM_DEBUG_VERBOSE
+ printf("random: %s %ld\n", __func__, uio->uio_resid);
+#endif
+
+ KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
+
+ sx_slock(&random_adaptors_lock);
+
+ /* Let the entropy source do any pre-read setup. */
+ (random_adaptor->ra_read)(NULL, 0);
+
+ /* (Un)Blocking logic */
+ error = 0;
+ while (!random_adaptor->ra_seeded()) {
+ if (flags & O_NONBLOCK) {
+ error = EWOULDBLOCK;
+ break;
+ }
+
+ /* Sleep instead of going into a spin-frenzy */
+ tsleep(&random_adaptor, PUSER | PCATCH, "block", hz/10);
+
+ /* keep tapping away at the pre-read until we seed/unblock. */
+ (random_adaptor->ra_read)(NULL, 0);
}
- primax = 0U;
- if (*adaptor == NULL) {
- /*
- * Fall back to the highest priority item on the available
- * RNG list.
- */
- sx_slock(&adaptors_lock);
+ mtx_lock(&random_read_rate_mtx);
- ramax = NULL;
- LIST_FOREACH(rppi, &adaptors, entries) {
- if (rppi->rsp->priority >= primax) {
- ramax = rppi;
- primax = rppi->rsp->priority;
- }
+ /* The read-rate stuff is a rough indication of the instantaneous read rate,
+ * used to increase the use of 'live' entropy sources when lots of reads are done.
+ */
+ nbytes = (uio->uio_resid + 32 - 1)/32; /* Round up to units of 32 */
+ random_adaptor_read_rate_cache += nbytes*32;
+ random_adaptor_read_rate_cache = MIN(random_adaptor_read_rate_cache, 32);
+
+ mtx_unlock(&random_read_rate_mtx);
+
+ if (!error) {
+
+ /* The actual read */
+
+ random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
+
+ while (uio->uio_resid && !error) {
+ c = MIN(uio->uio_resid, PAGE_SIZE);
+ (random_adaptor->ra_read)(random_buf, c);
+ error = uiomove(random_buf, c, uio);
}
- if (ramax != NULL)
- *adaptor = ramax->rsp;
- sx_sunlock(&adaptors_lock);
+ /* Let the entropy source do any post-read cleanup. */
+ (random_adaptor->ra_read)(NULL, 1);
- if (bootverbose && *adaptor)
- printf("Falling back to <%s> random adaptor\n",
- (*adaptor)->ident);
+ free(random_buf, M_ENTROPY);
}
+
+ sx_sunlock(&random_adaptors_lock);
+
+ return (error);
}
-static void
-random_adaptors_deinit(void *unused)
+int
+random_adaptor_read_rate(void)
{
+ int ret;
- sx_destroy(&adaptors_lock);
- sysctl_ctx_free(&random_clist);
+ KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
+
+ mtx_lock(&random_read_rate_mtx);
+
+ ret = random_adaptor_read_rate_cache;
+ random_adaptor_read_rate_cache = 1;
+
+ mtx_unlock(&random_read_rate_mtx);
+
+ return (ret);
}
-static int
-random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS)
+/* ARGSUSED */
+int
+random_adaptor_write(struct cdev *dev __unused, struct uio *uio, int flags __unused)
{
- struct random_adaptors *rpp;
- int error, count;
+ int c, error = 0;
+ void *random_buf;
- count = error = 0;
+#ifdef RANDOM_DEBUG
+ printf("random: %s %zd\n", __func__, uio->uio_resid);
+#endif
- sx_slock(&adaptors_lock);
+ KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
- if (LIST_EMPTY(&adaptors))
- error = SYSCTL_OUT(req, "", 0);
- else {
- LIST_FOREACH(rpp, &adaptors, entries) {
+ sx_slock(&random_adaptors_lock);
- error = SYSCTL_OUT(req, ",", count++ ? 1 : 0);
- if (error)
- break;
+ random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
- error = SYSCTL_OUT(req, rpp->name, strlen(rpp->name));
- if (error)
- break;
- }
+ while (uio->uio_resid > 0) {
+ c = MIN(uio->uio_resid, PAGE_SIZE);
+ error = uiomove(random_buf, c, uio);
+ if (error)
+ break;
+ (random_adaptor->ra_write)(random_buf, c);
+
+ /* Introduce an annoying delay to stop swamping */
+ tsleep(&random_adaptor, PUSER | PCATCH, "block", hz/10);
}
- sx_sunlock(&adaptors_lock);
+ free(random_buf, M_ENTROPY);
+
+ sx_sunlock(&random_adaptors_lock);
return (error);
}
-static int
-random_sysctl_active_adaptor_handler(SYSCTL_HANDLER_ARGS)
+/* ARGSUSED */
+int
+random_adaptor_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
{
- struct random_adaptor *rsp;
- struct random_adaptors *rpp;
- const char *name;
- int error;
- name = NULL;
- rsp = random_adaptor;
+#ifdef RANDOM_DEBUG
+ printf("random: %s\n", __func__);
+#endif
- if (rsp != NULL) {
- sx_slock(&adaptors_lock);
+ KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
- LIST_FOREACH(rpp, &adaptors, entries)
- if (rpp->rsp == rsp)
- name = rpp->name;
+ sx_slock(&random_adaptors_lock);
- sx_sunlock(&adaptors_lock);
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (random_adaptor->ra_seeded())
+ events &= (POLLIN | POLLRDNORM);
+ else
+ selrecord(td, &rsel);
}
- if (rsp == NULL || name == NULL)
- error = SYSCTL_OUT(req, "", 0);
- else
- error = SYSCTL_OUT(req, name, strlen(name));
+ sx_sunlock(&random_adaptors_lock);
+
+ return (events);
+}
+
+/* This will be called by the entropy processor when it seeds itself and becomes secure */
+void
+random_adaptor_unblock(void)
+{
+
+ selwakeuppri(&rsel, PUSER);
+ wakeup(&random_adaptor);
+ printf("random: unblocking device.\n");
+
+ /* Do arc4random(9) a favour while we are about it. */
+ (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, ARC4_ENTR_HAVE);
+}
+
+static int
+random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS)
+{
+ struct random_adaptors *rra;
+ struct sbuf sbuf;
+ int error, count;
+
+ sx_slock(&random_adaptors_lock);
+ sbuf_new_for_sysctl(&sbuf, NULL, 64, req);
+ count = 0;
+ LIST_FOREACH(rra, &random_adaptors_list, rra_entries)
+ sbuf_printf(&sbuf, "%s%s(%d)",
+ (count++ ? "," : ""), rra->rra_name, rra->rra_ra->ra_priority);
+
+ error = sbuf_finish(&sbuf);
+ sbuf_delete(&sbuf);
+ sx_sunlock(&random_adaptors_lock);
return (error);
}
-static void
-random_adaptors_init(void *unused)
+static int
+random_sysctl_active_adaptor_handler(SYSCTL_HANDLER_ARGS)
+{
+ struct random_adaptors *rra;
+ struct sbuf sbuf;
+ int error;
+
+ KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
+
+ sx_slock(&random_adaptors_lock);
+ sbuf_new_for_sysctl(&sbuf, NULL, 16, req);
+ LIST_FOREACH(rra, &random_adaptors_list, rra_entries)
+ if (rra->rra_ra == random_adaptor) {
+ sbuf_cat(&sbuf, rra->rra_name);
+ break;
+ }
+ error = sbuf_finish(&sbuf);
+ sbuf_delete(&sbuf);
+ sx_sunlock(&random_adaptors_lock);
+
+ return (error);
+}
+
+void
+random_adaptors_init(void)
{
+#ifdef RANDOM_DEBUG
+ printf("random: %s\n", __func__);
+#endif
+
SYSCTL_PROC(_kern_random, OID_AUTO, adaptors,
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
NULL, 0, random_sysctl_adaptors_handler, "A",
@@ -228,24 +416,74 @@ random_adaptors_init(void *unused)
NULL, 0, random_sysctl_active_adaptor_handler, "A",
"Active Random Number Generator Adaptor");
- sx_init(&adaptors_lock, "random_adaptors");
+ sx_init(&random_adaptors_lock, "random_adaptors");
+
+ mtx_init(&random_read_rate_mtx, "read rate mutex", NULL, MTX_DEF);
+
+ /* The dummy adaptor is not a module by itself, but part of the
+ * randomdev module.
+ */
+ random_adaptor_register("dummy", &randomdev_dummy);
+
+ live_entropy_sources_init();
}
-SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Random Number Generator");
+void
+random_adaptors_deinit(void)
+{
+
+#ifdef RANDOM_DEBUG
+ printf("random: %s\n", __func__);
+#endif
+
+ live_entropy_sources_deinit();
-SYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, random_adaptors_init,
- NULL);
-SYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST,
- random_adaptors_deinit, NULL);
+ /* Don't do this! Panic will surely follow! */
+ /* random_adaptor_deregister("dummy"); */
+ mtx_destroy(&random_read_rate_mtx);
+
+ sx_destroy(&random_adaptors_lock);
+}
+
+/*
+ * First seed.
+ *
+ * NB! NB! NB!
+ * NB! NB! NB!
+ *
+ * It turns out this is bloody dangerous. I was fiddling with code elsewhere
+ * and managed to get conditions where a safe (i.e. seeded) entropy device should
+ * not have been possible. This managed to hide that by unblocking the device anyway.
+ * As crap randomness is not directly distinguishable from good randomness, this
+ * could have gone unnoticed for quite a while.
+ *
+ * NB! NB! NB!
+ * NB! NB! NB!
+ *
+ * Very luckily, the probe-time entropy is very nearly good enough to cause a
+ * first seed all of the time, and the default settings for other entropy
+ * harvesting causes a proper, safe, first seed (unblock) in short order after that.
+ *
+ * That said, the below would be useful where folks are more concerned with
+ * a quick start than with extra paranoia in a low-entropy environment.
+ *
+ * markm - October 2013.
+ */
+#ifdef RANDOM_AUTOSEED
+/* ARGSUSED */
static void
-random_adaptors_reseed(void *unused)
+random_adaptors_seed(void *unused __unused)
{
+
+ KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
+
+ sx_slock(&random_adaptors_lock);
+ random_adaptor->ra_reseed();
+ sx_sunlock(&random_adaptors_lock);
- (void)unused;
- if (random_adaptor != NULL)
- (*random_adaptor->reseed)();
arc4rand(NULL, 0, 1);
}
-SYSINIT(random_reseed, SI_SUB_INTRINSIC_POST, SI_ORDER_SECOND,
+SYSINIT(random_seed, SI_SUB_INTRINSIC_POST, SI_ORDER_LAST,
random_adaptors_reseed, NULL);
+#endif /* RANDOM_AUTOSEED */
diff --git a/sys/dev/random/random_adaptors.h b/sys/dev/random/random_adaptors.h
index 4765694..08076ce 100644
--- a/sys/dev/random/random_adaptors.h
+++ b/sys/dev/random/random_adaptors.h
@@ -29,43 +29,46 @@
#ifndef SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED
#define SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED
-#include <sys/eventhandler.h>
-
MALLOC_DECLARE(M_ENTROPY);
+typedef void random_adaptor_init_func_t(void);
+typedef void random_adaptor_deinit_func_t(void);
+typedef void random_adaptor_read_func_t(uint8_t *, u_int);
+typedef void random_adaptor_write_func_t(uint8_t *, u_int);
+typedef int random_adaptor_seeded_func_t(void);
+typedef void random_adaptor_reseed_func_t(void);
+
+struct random_adaptor {
+ const char *ra_ident;
+ int ra_priority;
+ random_adaptor_init_func_t *ra_init;
+ random_adaptor_deinit_func_t *ra_deinit;
+ random_adaptor_read_func_t *ra_read;
+ random_adaptor_write_func_t *ra_write;
+ random_adaptor_reseed_func_t *ra_reseed;
+ random_adaptor_seeded_func_t *ra_seeded;
+};
+
struct random_adaptors {
- LIST_ENTRY(random_adaptors) entries; /* list of providers */
- const char *name; /* name of random adaptor */
- struct random_adaptor *rsp;
+ LIST_ENTRY(random_adaptors) rra_entries; /* list of providers */
+ const char *rra_name; /* name of random adaptor */
+ struct random_adaptor *rra_ra;
};
-struct random_adaptor *random_adaptor_get(const char *);
-int random_adaptor_register(const char *, struct random_adaptor *);
-void random_adaptor_choose(struct random_adaptor **);
+/* Dummy "always-block" pseudo-device */
+extern struct random_adaptor randomdev_dummy;
-extern struct random_adaptor *random_adaptor;
+void random_adaptors_init(void);
+void random_adaptors_deinit(void);
-/*
- * random_adaptor's should be registered prior to
- * random module (SI_SUB_DRIVERS/SI_ORDER_MIDDLE)
- */
-#define RANDOM_ADAPTOR_MODULE(name, modevent, ver) \
- static moduledata_t name##_mod = { \
- #name, \
- modevent, \
- 0 \
- }; \
- DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, \
- SI_ORDER_SECOND); \
- MODULE_VERSION(name, ver); \
- MODULE_DEPEND(name, random, 1, 1, 1);
+void random_adaptor_register(const char *, struct random_adaptor *);
+void random_adaptor_deregister(const char *);
-typedef void (*random_adaptor_attach_hook)(void *, struct random_adaptor *);
-EVENTHANDLER_DECLARE(random_adaptor_attach, random_adaptor_attach_hook);
+int random_adaptor_read(struct cdev *, struct uio *, int);
+int random_adaptor_write(struct cdev *, struct uio *, int);
+int random_adaptor_poll(struct cdev *, int, struct thread *);
-/* kern.random sysctls */
-#ifdef SYSCTL_DECL /* from sysctl.h */
-SYSCTL_DECL(_kern_random);
-#endif /* SYSCTL_DECL */
+int random_adaptor_read_rate(void);
+void random_adaptor_unblock(void);
#endif /* SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED */
diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c
index b7b8381..df6a853 100644
--- a/sys/dev/random/random_harvestq.c
+++ b/sys/dev/random/random_harvestq.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2000-2014 Mark R V Murray
* Copyright (c) 2013 Arthur Mesh
* Copyright (c) 2004 Robert N. M. Watson
* All rights reserved.
@@ -42,230 +42,293 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/random.h>
-#include <sys/selinfo.h>
+#include <sys/sbuf.h>
#include <sys/sysctl.h>
#include <sys/unistd.h>
#include <machine/cpu.h>
-#include <machine/vmparam.h>
#include <dev/random/randomdev.h>
-#include <dev/random/randomdev_soft.h>
#include <dev/random/random_adaptors.h>
#include <dev/random/random_harvestq.h>
#include <dev/random/live_entropy_sources.h>
-#include <dev/random/rwfile.h>
-#define RANDOM_FIFO_MAX 1024 /* How many events to queue up */
+/* List for the dynamic sysctls */
+static struct sysctl_ctx_list random_clist;
/*
- * The harvest mutex protects the consistency of the entropy fifos and
+ * How many events to queue up. We create this many items in
+ * an 'empty' queue, then transfer them to the 'harvest' queue with
+ * supplied junk. When used, they are transferred back to the
+ * 'empty' queue.
+ */
+#define RANDOM_FIFO_MAX 1024
+
+/*
+ * The harvest mutex protects the consistency of the entropy Fifos and
* empty fifo and other associated structures.
*/
-struct mtx harvest_mtx;
+static struct mtx harvest_mtx;
-/* Lockable FIFO queue holding entropy buffers */
-struct entropyfifo {
- int count;
- STAILQ_HEAD(harvestlist, harvest) head;
-};
+/*
+ * Lockable FIFO ring buffer holding entropy events
+ * If ring_in == ring_out,
+ * the buffer is empty.
+ * If (ring_in + 1) == ring_out (MOD RANDOM_FIFO_MAX),
+ * the buffer is full.
+ *
+ * The ring_in variable needs locking as there are multiple
+ * sources to the ring. Only the sources may change ring_in,
+ * but the consumer may examine it.
+ *
+ * The ring_out variable does not need locking as there is
+ * only one consumer. Only the consumer may change ring_out,
+ * but the sources may examine it.
+ */
+static struct entropyfifo {
+ struct harvest_event ring[RANDOM_FIFO_MAX];
+ volatile u_int ring_in;
+ volatile u_int ring_out;
+} entropyfifo;
+
+/* Round-robin destination cache. */
+u_int harvest_destination[ENTROPYSOURCE];
+
+/* Function called to process one harvested stochastic event */
+void (*harvest_process_event)(struct harvest_event *);
-/* Empty entropy buffers */
-static struct entropyfifo emptyfifo;
+/* Allow the sysadmin to select the broad category of
+ * entropy types to harvest.
+ */
+static u_int harvest_source_mask = ((1U << RANDOM_ENVIRONMENTAL_END) - 1);
-/* Harvested entropy */
-static struct entropyfifo harvestfifo;
+/* Pool count is used by anything needing to know how many entropy
+ * pools are currently being maintained.
+ * This is of use to (e.g.) the live source feed where we need to give
+ * all the pools a top-up.
+ */
+int harvest_pool_count;
/* <0 to end the kthread, 0 to let it run, 1 to flush the harvest queues */
-int random_kthread_control = 0;
+static int random_kthread_control = 0;
static struct proc *random_kthread_proc;
-#ifdef RANDOM_RWFILE
-static const char *entropy_files[] = {
- "/entropy",
- NULL
-};
-#endif
-
-/* Deal with entropy cached externally if this is present.
- * Lots of policy may eventually arrive in this function.
- * Called after / is mounted.
- */
static void
-random_harvestq_cache(void *arg __unused)
+random_kthread(void *arg __unused)
{
- uint8_t *keyfile, *data;
- size_t size, i;
-#ifdef RANDOM_RWFILE
- const char **entropy_file;
- uint8_t *zbuf;
- int error;
-#endif
-
- /* Get stuff that may have been preloaded by loader(8) */
- keyfile = preload_search_by_type("/boot/entropy");
- if (keyfile != NULL) {
- data = preload_fetch_addr(keyfile);
- size = preload_fetch_size(keyfile);
- if (data != NULL && size != 0) {
- for (i = 0; i < size; i += 16)
- random_harvestq_internal(get_cyclecount(), data + i, 16, 16, RANDOM_CACHED);
- printf("random: read %zu bytes from preloaded cache\n", size);
- bzero(data, size);
- }
- else
- printf("random: no preloaded entropy cache available\n");
- }
+ u_int maxloop, ring_out;
-#ifdef RANDOM_RWFILE
- /* Read and attempt to overwrite the entropy cache files.
- * If the file exists, can be read and then overwritten,
- * then use it. Ignore it otherwise, but print out what is
- * going on.
+ /*
+ * Process until told to stop.
+ *
+ * Locking is not needed as this is the only place we modify ring_out, and
+ * we only examine ring_in without changing it. Both of these are volatile,
+ * and this is a unique thread.
*/
- data = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
- zbuf = __DECONST(void *, zero_region);
- for (entropy_file = entropy_files; *entropy_file; entropy_file++) {
- error = randomdev_read_file(*entropy_file, data, PAGE_SIZE);
- if (error == 0) {
- printf("random: entropy cache '%s' provides %ld bytes\n", *entropy_file, (long)PAGE_SIZE);
- error = randomdev_write_file(*entropy_file, zbuf, PAGE_SIZE);
- if (error == 0) {
- printf("random: entropy cache '%s' contents used and successfully overwritten\n", *entropy_file);
- for (i = 0; i < PAGE_SIZE; i += 16)
- random_harvestq_internal(get_cyclecount(), data + i, 16, 16, RANDOM_CACHED);
- }
- else
- printf("random: entropy cache '%s' not overwritten and therefore not used; error = %d\n", *entropy_file, error);
- }
- else
- printf("random: entropy cache '%s' not present or unreadable; error = %d\n", *entropy_file, error);
- }
- bzero(data, PAGE_SIZE);
- free(data, M_ENTROPY);
-#endif
-}
-EVENTHANDLER_DEFINE(mountroot, random_harvestq_cache, NULL, 0);
+ while (random_kthread_control >= 0) {
-static void
-random_kthread(void *arg)
-{
- STAILQ_HEAD(, harvest) local_queue;
- struct harvest *event = NULL;
- int local_count;
- event_proc_f entropy_processor = arg;
+ /* Deal with events, if any. Restrict the number we do in one go. */
+ maxloop = RANDOM_FIFO_MAX;
+ while (entropyfifo.ring_out != entropyfifo.ring_in) {
- STAILQ_INIT(&local_queue);
- local_count = 0;
+ ring_out = (entropyfifo.ring_out + 1)%RANDOM_FIFO_MAX;
+ harvest_process_event(entropyfifo.ring + ring_out);
+ /* Modifying ring_out here ONLY. Sufficient for atomicity? */
+ entropyfifo.ring_out = ring_out;
- /* Process until told to stop */
- mtx_lock_spin(&harvest_mtx);
- for (; random_kthread_control >= 0;) {
-
- /*
- * Grab all the entropy events.
- * Drain entropy source records into a thread-local
- * queue for processing while not holding the mutex.
- */
- STAILQ_CONCAT(&local_queue, &harvestfifo.head);
- local_count += harvestfifo.count;
- harvestfifo.count = 0;
+ /* The ring may be filled quickly so don't loop forever. */
+ if (--maxloop)
+ break;
- /*
- * Deal with events, if any.
- * Then transfer the used events back into the empty fifo.
- */
- if (!STAILQ_EMPTY(&local_queue)) {
- mtx_unlock_spin(&harvest_mtx);
- STAILQ_FOREACH(event, &local_queue, next)
- entropy_processor(event);
- mtx_lock_spin(&harvest_mtx);
- STAILQ_CONCAT(&emptyfifo.head, &local_queue);
- emptyfifo.count += local_count;
- local_count = 0;
}
- KASSERT(local_count == 0, ("random_kthread: local_count %d",
- local_count));
-
/*
- * Do only one round of the hardware sources for now.
- * Later we'll need to make it rate-adaptive.
+ * Give the fast hardware sources a go
*/
- mtx_unlock_spin(&harvest_mtx);
- live_entropy_sources_feed(1, entropy_processor);
- mtx_lock_spin(&harvest_mtx);
+ live_entropy_sources_feed();
/*
* If a queue flush was commanded, it has now happened,
* and we can mark this by resetting the command.
+ * A negative value, however, terminates the thread.
*/
if (random_kthread_control == 1)
random_kthread_control = 0;
- /* Work done, so don't belabour the issue */
- msleep_spin_sbt(&random_kthread_control, &harvest_mtx,
- "-", SBT_1S/10, 0, C_PREL(1));
+ /* Some work is done, so give the rest of the OS a chance. */
+ tsleep_sbt(&random_kthread_control, 0, "-", SBT_1S/10, 0, C_PREL(1));
}
- mtx_unlock_spin(&harvest_mtx);
- random_set_wakeup_exit(&random_kthread_control);
+ randomdev_set_wakeup_exit(&random_kthread_control);
/* NOTREACHED */
}
void
-random_harvestq_init(event_proc_f cb)
+random_harvestq_flush(void)
+{
+
+ /* Command a entropy queue flush and wait for it to finish */
+ random_kthread_control = 1;
+ while (random_kthread_control)
+ pause("-", hz/10);
+}
+
+/* ARGSUSED */
+RANDOM_CHECK_UINT(harvestmask, 0, ((1U << RANDOM_ENVIRONMENTAL_END) - 1));
+
+/* ARGSUSED */
+static int
+random_print_harvestmask(SYSCTL_HANDLER_ARGS)
{
+ struct sbuf sbuf;
int error, i;
- struct harvest *np;
- /* Initialise the harvest fifos */
+ error = sysctl_wire_old_buffer(req, 0);
+ if (error == 0) {
+ sbuf_new_for_sysctl(&sbuf, NULL, 128, req);
+ for (i = RANDOM_ENVIRONMENTAL_END - 1; i >= 0; i--)
+ sbuf_cat(&sbuf, (harvest_source_mask & (1U << i)) ? "1" : "0");
+ error = sbuf_finish(&sbuf);
+ sbuf_delete(&sbuf);
+ }
+
+ return (error);
+}
- /* Contains the currently unused event structs. */
- STAILQ_INIT(&emptyfifo.head);
- for (i = 0; i < RANDOM_FIFO_MAX; i++) {
- np = malloc(sizeof(struct harvest), M_ENTROPY, M_WAITOK);
- STAILQ_INSERT_TAIL(&emptyfifo.head, np, next);
+static const char *(random_source_descr[]) = {
+ "CACHED",
+ "ATTACH",
+ "KEYBOARD",
+ "MOUSE",
+ "NET_TUN",
+ "NET_ETHER",
+ "NET_NG",
+ "INTERRUPT",
+ "SWI",
+ "UMA_ALLOC",
+ "", /* "ENVIRONMENTAL_END" */
+ "PURE_OCTEON",
+ "PURE_SAFE",
+ "PURE_GLXSB",
+ "PURE_UBSEC",
+ "PURE_HIFN",
+ "PURE_RDRAND",
+ "PURE_NEHEMIAH",
+ "PURE_RNDTEST",
+ /* "ENTROPYSOURCE" */
+};
+
+/* ARGSUSED */
+static int
+random_print_harvestmask_symbolic(SYSCTL_HANDLER_ARGS)
+{
+ struct sbuf sbuf;
+ int error, i;
+
+ error = sysctl_wire_old_buffer(req, 0);
+ if (error == 0) {
+ sbuf_new_for_sysctl(&sbuf, NULL, 128, req);
+ for (i = RANDOM_ENVIRONMENTAL_END - 1; i >= 0; i--) {
+ sbuf_cat(&sbuf, (i == RANDOM_ENVIRONMENTAL_END - 1) ? "" : ",");
+ sbuf_cat(&sbuf, (harvest_source_mask & (1U << i)) ? random_source_descr[i] : "");
+ }
+ error = sbuf_finish(&sbuf);
+ sbuf_delete(&sbuf);
}
- emptyfifo.count = RANDOM_FIFO_MAX;
- /* Will contain the queued-up events. */
- STAILQ_INIT(&harvestfifo.head);
- harvestfifo.count = 0;
+ return (error);
+}
+void
+random_harvestq_init(void (*event_processor)(struct harvest_event *), int poolcount)
+{
+ uint8_t *keyfile, *data;
+ int error;
+ size_t size, j;
+ struct sysctl_oid *random_sys_o;
+
+#ifdef RANDOM_DEBUG
+ printf("random: %s\n", __func__);
+#endif
+
+ random_sys_o = SYSCTL_ADD_NODE(&random_clist,
+ SYSCTL_STATIC_CHILDREN(_kern_random),
+ OID_AUTO, "harvest", CTLFLAG_RW, 0,
+ "Entropy Device Parameters");
+
+ SYSCTL_ADD_PROC(&random_clist,
+ SYSCTL_CHILDREN(random_sys_o),
+ OID_AUTO, "mask", CTLTYPE_UINT | CTLFLAG_RW,
+ &harvest_source_mask, ((1U << RANDOM_ENVIRONMENTAL_END) - 1),
+ random_check_uint_harvestmask, "IU",
+ "Entropy harvesting mask");
+
+ SYSCTL_ADD_PROC(&random_clist,
+ SYSCTL_CHILDREN(random_sys_o),
+ OID_AUTO, "mask_bin", CTLTYPE_STRING | CTLFLAG_RD,
+ NULL, 0, random_print_harvestmask, "A", "Entropy harvesting mask (printable)");
+
+ SYSCTL_ADD_PROC(&random_clist,
+ SYSCTL_CHILDREN(random_sys_o),
+ OID_AUTO, "mask_symbolic", CTLTYPE_STRING | CTLFLAG_RD,
+ NULL, 0, random_print_harvestmask_symbolic, "A", "Entropy harvesting mask (symbolic)");
+
+ /* Point to the correct event_processing function */
+ harvest_process_event = event_processor;
+
+ /* Store the pool count (used by live source feed) */
+ harvest_pool_count = poolcount;
+
+ /* Initialise the harvesting mutex and in/out indexes. */
mtx_init(&harvest_mtx, "entropy harvest mutex", NULL, MTX_SPIN);
+ entropyfifo.ring_in = entropyfifo.ring_out = 0U;
/* Start the hash/reseed thread */
- error = kproc_create(random_kthread, cb,
- &random_kthread_proc, RFHIGHPID, 0, "rand_harvestq"); /* RANDOM_CSPRNG_NAME */
+ error = kproc_create(random_kthread, NULL,
+ &random_kthread_proc, RFHIGHPID, 0, "rand_harvestq");
if (error != 0)
panic("Cannot create entropy maintenance thread.");
+
+ /* Get entropy that may have been preloaded by loader(8)
+ * and use it to pre-charge the entropy harvest queue.
+ */
+ keyfile = preload_search_by_type("/boot/entropy");
+ if (keyfile != NULL) {
+ data = preload_fetch_addr(keyfile);
+ size = preload_fetch_size(keyfile);
+ if (data != NULL && size != 0) {
+ for (j = 0; j < size; j += 16)
+ random_harvestq_internal(data + j, 16, 16, RANDOM_CACHED);
+ printf("random: read %zu bytes from preloaded cache\n", size);
+ bzero(data, size);
+ }
+ else
+ printf("random: no preloaded entropy cache\n");
+ }
+
}
void
random_harvestq_deinit(void)
{
- struct harvest *np;
- /* Destroy the harvest fifos */
- while (!STAILQ_EMPTY(&emptyfifo.head)) {
- np = STAILQ_FIRST(&emptyfifo.head);
- STAILQ_REMOVE_HEAD(&emptyfifo.head, next);
- free(np, M_ENTROPY);
- }
- emptyfifo.count = 0;
- while (!STAILQ_EMPTY(&harvestfifo.head)) {
- np = STAILQ_FIRST(&harvestfifo.head);
- STAILQ_REMOVE_HEAD(&harvestfifo.head, next);
- free(np, M_ENTROPY);
- }
- harvestfifo.count = 0;
+#ifdef RANDOM_DEBUG
+ printf("random: %s\n", __func__);
+#endif
+
+ /*
+ * Command the hash/reseed thread to end and wait for it to finish
+ */
+ random_kthread_control = -1;
+ tsleep(&random_kthread_control, 0, "term", 0);
mtx_destroy(&harvest_mtx);
+
+ sysctl_ctx_free(&random_clist);
}
/*
@@ -278,45 +341,42 @@ random_harvestq_deinit(void)
* check a few lines below. This includes the "always-on" sources
* like the Intel "rdrand" or the VIA Nehamiah "xstore" sources.
*/
+/* XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle
+ * counters are built in, but on older hardware it will do a real time clock
+ * read which can be quite expensive.
+ */
void
-random_harvestq_internal(u_int64_t somecounter, const void *entropy,
- u_int count, u_int bits, enum esource origin)
+random_harvestq_internal(const void *entropy, u_int count, u_int bits,
+ enum random_entropy_source origin)
{
- struct harvest *event;
+ struct harvest_event *event;
+ u_int ring_in;
KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE,
("random_harvest_internal: origin %d invalid\n", origin));
- /* Lockless read to avoid lock operations if fifo is full. */
- if (harvestfifo.count >= RANDOM_FIFO_MAX)
+ /* Mask out unwanted sources */
+ if (!(harvest_source_mask & (1U << origin)))
return;
+ /* Lock ring_in against multi-thread contention */
mtx_lock_spin(&harvest_mtx);
-
- /*
- * On't overfill the harvest queue; this could steal all
- * our memory.
- */
- if (harvestfifo.count < RANDOM_FIFO_MAX) {
- event = STAILQ_FIRST(&emptyfifo.head);
- if (event != NULL) {
- /* Add the harvested data to the fifo */
- STAILQ_REMOVE_HEAD(&emptyfifo.head, next);
- emptyfifo.count--;
- event->somecounter = somecounter;
- event->size = count;
- event->bits = bits;
- event->source = origin;
-
- /* XXXX Come back and make this dynamic! */
- count = MIN(count, HARVESTSIZE);
- memcpy(event->entropy, entropy, count);
-
- STAILQ_INSERT_TAIL(&harvestfifo.head,
- event, next);
- harvestfifo.count++;
- }
+ ring_in = (entropyfifo.ring_in + 1)%RANDOM_FIFO_MAX;
+ if (ring_in != entropyfifo.ring_out) {
+ /* The ring is not full */
+ event = entropyfifo.ring + ring_in;
+
+ /* Stash the harvested stuff in the *event buffer */
+ count = MIN(count, HARVESTSIZE);
+ event->he_somecounter = get_cyclecount();
+ event->he_size = count;
+ event->he_bits = bits;
+ event->he_source = origin;
+ event->he_destination = harvest_destination[origin]++;
+ memcpy(event->he_entropy, entropy, count);
+ memset(event->he_entropy + count, 0, HARVESTSIZE - count);
+
+ entropyfifo.ring_in = ring_in;
}
-
mtx_unlock_spin(&harvest_mtx);
}
diff --git a/sys/dev/random/random_harvestq.h b/sys/dev/random/random_harvestq.h
index a2ac3d1..ab09a3f 100644
--- a/sys/dev/random/random_harvestq.h
+++ b/sys/dev/random/random_harvestq.h
@@ -1,4 +1,5 @@
/*-
+ * Copyright (c) 2013-2014 Mark R V Murray
* Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
* All rights reserved.
*
@@ -29,14 +30,41 @@
#ifndef SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED
#define SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED
-typedef void (*event_proc_f)(struct harvest *event);
+#define HARVESTSIZE 16 /* max size of each harvested entropy unit */
-void random_harvestq_init(event_proc_f);
+/* These are used to queue harvested packets of entropy. The entropy
+ * buffer size is pretty arbitrary.
+ */
+struct harvest_event {
+ uintmax_t he_somecounter; /* fast counter for clock jitter */
+ uint8_t he_entropy[HARVESTSIZE];/* some harvested entropy */
+ u_int he_size; /* harvested entropy byte count */
+ u_int he_bits; /* stats about the entropy */
+ u_int he_destination; /* destination pool of this entropy */
+ enum random_entropy_source he_source; /* origin of the entropy */
+};
+
+void random_harvestq_init(void (*)(struct harvest_event *), int);
void random_harvestq_deinit(void);
-void random_harvestq_internal(u_int64_t, const void *,
- u_int, u_int, enum esource);
+void random_harvestq_internal(const void *, u_int, u_int, enum random_entropy_source);
+
+/* Pool count is used by anything needing to know how many entropy
+ * pools are currently being maintained.
+ * This is of use to (e.g.) the live source feed where we need to give
+ * all the pools a top-up.
+ */
+extern int harvest_pool_count;
+
+/* This is in randomdev.c as it needs to be permanently in the kernel */
+void randomdev_set_wakeup_exit(void *);
+
+/* Force all currently pending queue contents to clear, and kick the software processor */
+void random_harvestq_flush(void);
+
+/* Function called to process one harvested stochastic event */
+extern void (*harvest_process_event)(struct harvest_event *);
-extern int random_kthread_control;
-extern struct mtx harvest_mtx;
+/* Round-robin destination cache. */
+extern u_int harvest_destination[ENTROPYSOURCE];
#endif /* SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED */
diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c
index b76cb83..bc41d51 100644
--- a/sys/dev/random/randomdev.c
+++ b/sys/dev/random/randomdev.c
@@ -26,9 +26,28 @@
*
*/
+/*
+ * NOTE NOTE NOTE
+ *
+ * This file is compiled into the kernel unconditionally. Any random(4)
+ * infrastructure that needs to be in the kernel by default goes here!
+ *
+ * Except ...
+ *
+ * The adaptor code all goes into random_adaptor.c, which is also compiled
+ * the kernel by default. The module in that file is initialised before
+ * this one.
+ *
+ * Other modules must be initialised after the above two, and are
+ * software random processors which plug into random_adaptor.c.
+ *
+ */
+
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_random.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -38,196 +57,196 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/lock.h>
-#include <sys/malloc.h>
#include <sys/module.h>
-#include <sys/mutex.h>
-#include <sys/poll.h>
-#include <sys/priv.h>
+#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/random.h>
-#include <sys/selinfo.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
#include <sys/uio.h>
#include <sys/unistd.h>
-#include <machine/bus.h>
-#include <machine/cpu.h>
-
#include <dev/random/randomdev.h>
-#include <dev/random/randomdev_soft.h>
#include <dev/random/random_adaptors.h>
#include <dev/random/random_harvestq.h>
-#include <dev/random/live_entropy_sources.h>
#define RANDOM_MINOR 0
-static d_read_t random_read;
-static d_write_t random_write;
-static d_ioctl_t random_ioctl;
-static d_poll_t random_poll;
+static d_ioctl_t randomdev_ioctl;
static struct cdevsw random_cdevsw = {
- .d_version = D_VERSION,
- .d_read = random_read,
- .d_write = random_write,
- .d_ioctl = random_ioctl,
- .d_poll = random_poll,
.d_name = "random",
+ .d_version = D_VERSION,
+ .d_read = random_adaptor_read,
+ .d_write = random_adaptor_write,
+ .d_poll = random_adaptor_poll,
+ .d_ioctl = randomdev_ioctl,
};
/* 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, "Random Number Generator");
+
+MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures");
+
/* ARGSUSED */
static int
-random_read(struct cdev *dev __unused, struct uio *uio, int flag)
+randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
+ int flags __unused, struct thread *td __unused)
{
- int c, error = 0;
- void *random_buf;
-
- /* Blocking logic */
- if (!random_adaptor->seeded)
- error = (*random_adaptor->block)(flag);
-
- /* The actual read */
- if (!error) {
-
- random_buf = (void *)malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
+ int error = 0;
- while (uio->uio_resid > 0 && !error) {
- c = MIN(uio->uio_resid, PAGE_SIZE);
- c = (*random_adaptor->read)(random_buf, c);
- error = uiomove(random_buf, c, uio);
- }
- /* Finished reading; let the source know so it can do some
- * optional housekeeping */
- (*random_adaptor->read)(NULL, 0);
+ switch (cmd) {
+ /* Really handled in upper layer */
+ case FIOASYNC:
+ case FIONBIO:
+ break;
- free(random_buf, M_ENTROPY);
+ default:
+ error = ENOTTY;
}
return (error);
}
-/* ARGSUSED */
-static int
-random_write(struct cdev *dev __unused, struct uio *uio, int flag __unused)
+/* Helper routine to enable kproc_exit() to work while the module is
+ * being (or has been) unloaded.
+ * This routine is in this file because it is always linked into the kernel,
+ * and will thus never be unloaded. This is critical for unloadable modules
+ * that have threads.
+ */
+void
+randomdev_set_wakeup_exit(void *control)
{
- /* We used to allow this to insert userland entropy.
- * We don't any more because (1) this so-called entropy
- * is usually lousy and (b) its vaguely possible to
- * mess with entropy harvesting by overdoing a write.
- * Now we just ignore input like /dev/null does.
- */
- uio->uio_resid = 0;
-
- return (0);
+ wakeup(control);
+ kproc_exit(0);
+ /* NOTREACHED */
}
/* ARGSUSED */
static int
-random_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
- int flags __unused, struct thread *td __unused)
+randomdev_modevent(module_t mod __unused, int type, void *data __unused)
{
int error = 0;
- switch (cmd) {
- /* Really handled in upper layer */
- case FIOASYNC:
- case FIONBIO:
+ switch (type) {
+ case MOD_LOAD:
+ printf("random: entropy device infrastructure driver\n");
+ random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw,
+ RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0644, "random");
+ make_dev_alias(random_dev, "urandom"); /* compatibility */
+ random_adaptors_init();
break;
+
+ case MOD_UNLOAD:
+ random_adaptors_deinit();
+ destroy_dev(random_dev);
+ break;
+
+ case MOD_SHUTDOWN:
+ break;
+
default:
- error = ENOTTY;
+ error = EOPNOTSUPP;
+ break;
+
}
+
return (error);
}
-/* ARGSUSED */
-static int
-random_poll(struct cdev *dev __unused, int events, struct thread *td)
-{
- int revents = 0;
+#define EARLY_2_DEV_MODULE(name, evh, arg) \
+static moduledata_t name##_mod = { \
+ #name, \
+ evh, \
+ arg \
+}; \
+DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND)
- if (events & (POLLIN | POLLRDNORM)) {
- if (random_adaptor->seeded)
- revents = events & (POLLIN | POLLRDNORM);
- else
- revents = (*random_adaptor->poll)(events, td);
- }
- return (revents);
-}
+EARLY_2_DEV_MODULE(randomdev, randomdev_modevent, NULL);
+MODULE_VERSION(randomdev, 1);
+
+/* ================
+ * Harvesting stubs
+ * ================
+ */
+/* Internal stub/fake routine for when no entropy processor is loaded.
+ * If the entropy device is not loaded, don't act on harvesting calls
+ * and just return.
+ */
+/* ARGSUSED */
static void
-random_initialize(void *p, struct random_adaptor *s)
+random_harvest_phony(const void *entropy __unused, u_int count __unused,
+ u_int bits __unused, enum random_entropy_source origin __unused)
{
- static int random_inited = 0;
-
- if (random_inited) {
- printf("random: <%s> already initialized\n",
- random_adaptor->ident);
- return;
- }
+}
- random_adaptor = s;
+/* Hold the address of the routine which is actually called */
+static void (*reap_func)(const void *, u_int, u_int, enum random_entropy_source) = random_harvest_phony;
- (s->init)();
+/* Initialise the harvester when/if it is loaded */
+void
+randomdev_init_harvester(void (*reaper)(const void *, u_int, u_int, enum random_entropy_source))
+{
- printf("random: <%s> initialized\n", s->ident);
+ reap_func = reaper;
+}
- /* Use an appropriately evil mode for those who are concerned
- * with daemons */
- random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw,
- RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0666, "random");
- make_dev_alias(random_dev, "urandom"); /* compatibility */
+/* Deinitialise the harvester when/if it is unloaded */
+void
+randomdev_deinit_harvester(void)
+{
- /* mark random(4) as initialized, to avoid being called again */
- random_inited = 1;
+ reap_func = random_harvest_phony;
}
-/* ARGSUSED */
-static int
-random_modevent(module_t mod __unused, int type, void *data __unused)
+/* Entropy harvesting routine.
+ * Implemented as in indirect call to allow non-inclusion of
+ * the entropy device.
+ */
+void
+random_harvest(const void *entropy, u_int count, u_int bits, enum random_entropy_source origin)
{
- static eventhandler_tag attach_tag = NULL;
- int error = 0;
-
- switch (type) {
- case MOD_LOAD:
- random_adaptor_choose(&random_adaptor);
- if (random_adaptor == NULL) {
- printf("random: No random adaptor attached, "
- "postponing initialization\n");
- attach_tag = EVENTHANDLER_REGISTER(random_adaptor_attach,
- random_initialize, NULL, EVENTHANDLER_PRI_ANY);
- } else
- random_initialize(NULL, random_adaptor);
+ (*reap_func)(entropy, count, bits, origin);
+}
- break;
+/* ================================
+ * Internal reading stubs and fakes
+ * ================================
+ */
- case MOD_UNLOAD:
- if (random_adaptor != NULL) {
- (*random_adaptor->deinit)();
- destroy_dev(random_dev);
- }
- /* Unregister the event handler */
- if (attach_tag != NULL)
- EVENTHANDLER_DEREGISTER(random_adaptor_attach,
- attach_tag);
+/* Hold the address of the routine which is actually called */
+static u_int (*read_func)(uint8_t *, u_int) = dummy_random_read_phony;
- break;
+/* Initialise the reader when/if it is loaded */
+void
+randomdev_init_reader(u_int (*reader)(uint8_t *, u_int))
+{
- case MOD_SHUTDOWN:
- break;
+ read_func = reader;
+}
- default:
- error = EOPNOTSUPP;
- break;
+/* Deinitialise the reader when/if it is unloaded */
+void
+randomdev_deinit_reader(void)
+{
- }
- return (error);
+ read_func = dummy_random_read_phony;
}
-DEV_MODULE(random, random_modevent, NULL);
-MODULE_VERSION(random, 1);
+/* Kernel API version of read_random().
+ * Implemented as in indirect call to allow non-inclusion of
+ * the entropy device.
+ */
+int
+read_random(void *buf, int count)
+{
+
+ return ((int)(*read_func)(buf, (u_int)count));
+}
diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h
index b87789f..4daf735 100644
--- a/sys/dev/random/randomdev.h
+++ b/sys/dev/random/randomdev.h
@@ -35,28 +35,33 @@
typedef void random_init_func_t(void);
typedef void random_deinit_func_t(void);
-typedef int random_block_func_t(int);
-typedef int random_read_func_t(void *, int);
-typedef int random_poll_func_t(int, struct thread *);
-typedef void random_reseed_func_t(void);
-
-struct random_adaptor {
- struct selinfo rsel;
- const char *ident;
- int seeded;
- unsigned priority;
- random_init_func_t *init;
- random_deinit_func_t *deinit;
- random_block_func_t *block;
- random_read_func_t *read;
- random_poll_func_t *poll;
- random_reseed_func_t *reseed;
-};
-
-struct random_hardware_source {
- const char *ident;
- enum esource source;
- random_read_func_t *read;
-};
+
+void randomdev_init_harvester(void (*)(const void *, u_int, u_int, enum random_entropy_source));
+void randomdev_init_reader(u_int (*)(uint8_t *, u_int));
+void randomdev_deinit_harvester(void);
+void randomdev_deinit_reader(void);
+
+/* Stub/fake routines for when no entropy processor is loaded */
+extern u_int dummy_random_read_phony(uint8_t *, u_int);
+
+/* kern.random sysctls */
+#ifdef SYSCTL_DECL /* from sysctl.h */
+SYSCTL_DECL(_kern_random);
+
+/* If this was C++, the macro below would be a template */
+#define RANDOM_CHECK_UINT(name, min, max) \
+static int \
+random_check_uint_##name(SYSCTL_HANDLER_ARGS) \
+{ \
+ if (oidp->oid_arg1 != NULL) { \
+ if (*(u_int *)(oidp->oid_arg1) <= (min)) \
+ *(u_int *)(oidp->oid_arg1) = (min); \
+ else if (*(u_int *)(oidp->oid_arg1) > (max)) \
+ *(u_int *)(oidp->oid_arg1) = (max); \
+ } \
+ return (sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, \
+ req)); \
+}
+#endif /* SYSCTL_DECL */
#endif
diff --git a/sys/dev/random/randomdev_soft.c b/sys/dev/random/randomdev_soft.c
index 0929704..61cdf35 100644
--- a/sys/dev/random/randomdev_soft.c
+++ b/sys/dev/random/randomdev_soft.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2000-2014 Mark R V Murray
* Copyright (c) 2004 Robert N. M. Watson
* All rights reserved.
*
@@ -26,6 +26,16 @@
*
*/
+/*
+ * This is the loadable infrastructure base file for software CSPRNG
+ * drivers such as Yarrow or Fortuna.
+ *
+ * It is anticipated that one instance of this file will be used
+ * for _each_ invocation of a CSPRNG, but with different #defines
+ * set. See below.
+ *
+ */
+
#include "opt_random.h"
#if !defined(RANDOM_YARROW) && !defined(RANDOM_FORTUNA)
@@ -33,15 +43,13 @@
#elif defined(RANDOM_YARROW) && defined(RANDOM_FORTUNA)
#error "Must define either RANDOM_YARROW or RANDOM_FORTUNA"
#endif
-#if defined(RANDOM_FORTUNA)
-#error "Fortuna is not yet implemented"
-#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/lock.h>
@@ -50,14 +58,9 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/poll.h>
#include <sys/random.h>
-#include <sys/selinfo.h>
#include <sys/sysctl.h>
-#include <sys/uio.h>
#include <sys/unistd.h>
-#include <machine/bus.h>
-#include <machine/cpu.h>
-
#include <dev/random/randomdev.h>
#include <dev/random/randomdev_soft.h>
#include <dev/random/random_harvestq.h>
@@ -69,111 +72,44 @@ __FBSDID("$FreeBSD$");
#include <dev/random/fortuna.h>
#endif
-
-static int randomdev_poll(int event, struct thread *td);
-static int randomdev_block(int flag);
-static void randomdev_flush_reseed(void);
-
+static struct random_adaptor random_soft_processor = {
#if defined(RANDOM_YARROW)
-static struct random_adaptor random_context = {
- .ident = "Software, Yarrow",
- .init = randomdev_init,
- .deinit = randomdev_deinit,
- .block = randomdev_block,
- .read = random_yarrow_read,
- .poll = randomdev_poll,
- .reseed = randomdev_flush_reseed,
- .seeded = 0, /* This will be seeded during entropy processing */
- .priority = 90, /* High priority, so top of the list. Fortuna may still win. */
-};
-#define RANDOM_MODULE_NAME yarrow
#define RANDOM_CSPRNG_NAME "yarrow"
+ .ra_ident = "Yarrow",
+ .ra_priority = 90, /* High priority, so top of the list. Fortuna may still win. */
+ .ra_read = random_yarrow_read,
+ .ra_write = random_yarrow_write,
+ .ra_reseed = random_yarrow_reseed,
+ .ra_seeded = random_yarrow_seeded,
#endif
-
#if defined(RANDOM_FORTUNA)
-static struct random_adaptor random_context = {
- .ident = "Software, Fortuna",
- .init = randomdev_init,
- .deinit = randomdev_deinit,
- .block = randomdev_block,
- .read = random_fortuna_read,
- .poll = randomdev_poll,
- .reseed = randomdev_flush_reseed,
- .seeded = 0, /* This will be excplicitly seeded at startup when secured */
- .priority = 100, /* High priority, so top of the list. Beat Yarrow. */
-};
-#define RANDOM_MODULE_NAME fortuna
#define RANDOM_CSPRNG_NAME "fortuna"
+ .ra_ident = "Fortuna",
+ .ra_priority = 100, /* High priority, so top of the list. Beat Yarrow. */
+ .ra_read = random_fortuna_read,
+ .ra_write = random_fortuna_write,
+ .ra_reseed = random_fortuna_reseed,
+ .ra_seeded = random_fortuna_seeded,
#endif
-
-TUNABLE_INT("kern.random.sys.seeded", &random_context.seeded);
-
-/* List for the dynamic sysctls */
-static struct sysctl_ctx_list random_clist;
-
-/* ARGSUSED */
-static int
-random_check_boolean(SYSCTL_HANDLER_ARGS)
-{
- if (oidp->oid_arg1 != NULL && *(u_int *)(oidp->oid_arg1) != 0)
- *(u_int *)(oidp->oid_arg1) = 1;
- return (sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req));
-}
+ .ra_init = randomdev_init,
+ .ra_deinit = randomdev_deinit,
+};
void
randomdev_init(void)
{
- struct sysctl_oid *random_sys_o, *random_sys_harvest_o;
#if defined(RANDOM_YARROW)
- random_yarrow_init_alg(&random_clist);
+ random_yarrow_init_alg();
+ random_harvestq_init(random_yarrow_process_event, 2);
#endif
#if defined(RANDOM_FORTUNA)
- random_fortuna_init_alg(&random_clist);
+ random_fortuna_init_alg();
+ random_harvestq_init(random_fortuna_process_event, 32);
#endif
- random_sys_o = SYSCTL_ADD_NODE(&random_clist,
- SYSCTL_STATIC_CHILDREN(_kern_random),
- OID_AUTO, "sys", CTLFLAG_RW, 0,
- "Entropy Device Parameters");
-
- SYSCTL_ADD_PROC(&random_clist,
- SYSCTL_CHILDREN(random_sys_o),
- OID_AUTO, "seeded", CTLTYPE_INT | CTLFLAG_RW,
- &random_context.seeded, 0, random_check_boolean, "I",
- "Seeded State");
-
- random_sys_harvest_o = SYSCTL_ADD_NODE(&random_clist,
- SYSCTL_CHILDREN(random_sys_o),
- OID_AUTO, "harvest", CTLFLAG_RW, 0,
- "Entropy Sources");
-
- SYSCTL_ADD_PROC(&random_clist,
- SYSCTL_CHILDREN(random_sys_harvest_o),
- OID_AUTO, "ethernet", CTLTYPE_INT | CTLFLAG_RW,
- &harvest.ethernet, 1, random_check_boolean, "I",
- "Harvest NIC entropy");
- SYSCTL_ADD_PROC(&random_clist,
- SYSCTL_CHILDREN(random_sys_harvest_o),
- OID_AUTO, "point_to_point", CTLTYPE_INT | CTLFLAG_RW,
- &harvest.point_to_point, 1, random_check_boolean, "I",
- "Harvest serial net entropy");
- SYSCTL_ADD_PROC(&random_clist,
- SYSCTL_CHILDREN(random_sys_harvest_o),
- OID_AUTO, "interrupt", CTLTYPE_INT | CTLFLAG_RW,
- &harvest.interrupt, 1, random_check_boolean, "I",
- "Harvest IRQ entropy");
- SYSCTL_ADD_PROC(&random_clist,
- SYSCTL_CHILDREN(random_sys_harvest_o),
- OID_AUTO, "swi", CTLTYPE_INT | CTLFLAG_RW,
- &harvest.swi, 1, random_check_boolean, "I",
- "Harvest SWI entropy");
-
- random_harvestq_init(random_process_event);
-
/* Register the randomness harvesting routine */
- randomdev_init_harvester(random_harvestq_internal,
- random_context.read);
+ randomdev_init_harvester(random_harvestq_internal);
}
void
@@ -182,118 +118,56 @@ randomdev_deinit(void)
/* Deregister the randomness harvesting routine */
randomdev_deinit_harvester();
- /*
- * Command the hash/reseed thread to end and wait for it to finish
- */
- random_kthread_control = -1;
- tsleep((void *)&random_kthread_control, 0, "term", 0);
-
#if defined(RANDOM_YARROW)
random_yarrow_deinit_alg();
#endif
#if defined(RANDOM_FORTUNA)
random_fortuna_deinit_alg();
#endif
-
- sysctl_ctx_free(&random_clist);
-}
-
-void
-randomdev_unblock(void)
-{
- if (!random_context.seeded) {
- selwakeuppri(&random_context.rsel, PUSER);
- wakeup(&random_context);
- printf("random: unblocking device.\n");
- random_context.seeded = 1;
- }
- /* Do arc4random(9) a favour while we are about it. */
- (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE,
- ARC4_ENTR_HAVE);
}
+/* ARGSUSED */
static int
-randomdev_poll(int events, struct thread *td)
+randomdev_soft_modevent(module_t mod __unused, int type, void *unused __unused)
{
- int revents = 0;
-
- mtx_lock(&random_reseed_mtx);
+ int error = 0;
- if (random_context.seeded)
- revents = events & (POLLIN | POLLRDNORM);
- else
- selrecord(td, &random_context.rsel);
+ switch (type) {
+ case MOD_LOAD:
+ printf("random: SOFT: %s init()\n", RANDOM_CSPRNG_NAME);
+ random_adaptor_register(RANDOM_CSPRNG_NAME, &random_soft_processor);
+ break;
- mtx_unlock(&random_reseed_mtx);
- return (revents);
-}
+ case MOD_UNLOAD:
+ random_adaptor_deregister(RANDOM_CSPRNG_NAME);
+ break;
-static int
-randomdev_block(int flag)
-{
- int error = 0;
+ case MOD_SHUTDOWN:
+ break;
- mtx_lock(&random_reseed_mtx);
+ default:
+ error = EOPNOTSUPP;
+ break;
- /* Blocking logic */
- while (!random_context.seeded && !error) {
- if (flag & O_NONBLOCK)
- error = EWOULDBLOCK;
- else {
- printf("random: blocking on read.\n");
- error = msleep(&random_context,
- &random_reseed_mtx,
- PUSER | PCATCH, "block", 0);
- }
}
- mtx_unlock(&random_reseed_mtx);
-
return (error);
}
-/* Helper routine to perform explicit reseeds */
-static void
-randomdev_flush_reseed(void)
-{
- /* Command a entropy queue flush and wait for it to finish */
- random_kthread_control = 1;
- while (random_kthread_control)
- pause("-", hz / 10);
+#define MID_DEV_MODULE(name, evh, arg) \
+static moduledata_t name##_mod = { \
+ #name, \
+ evh, \
+ arg \
+}; \
+DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE)
#if defined(RANDOM_YARROW)
- /* This ultimately calls randomdev_unblock() */
- random_yarrow_reseed();
+MID_DEV_MODULE(yarrow, randomdev_soft_modevent, NULL);
+MODULE_VERSION(yarrow, 1);
+MODULE_DEPEND(yarrow, random_adaptors, 1, 1, 1);
#endif
#if defined(RANDOM_FORTUNA)
- /* This ultimately calls randomdev_unblock() */
- random_fortuna_reseed();
+MID_DEV_MODULE(fortuna, randomdev_soft_modevent, NULL);
+MODULE_VERSION(fortuna, 1);
+MODULE_DEPEND(fortuna, random_adaptors, 1, 1, 1);
#endif
-}
-
-static int
-randomdev_modevent(module_t mod __unused, int type, void *unused __unused)
-{
-
- switch (type) {
- case MOD_LOAD:
- random_adaptor_register(RANDOM_CSPRNG_NAME, &random_context);
- /*
- * For statically built kernels that contain both device
- * random and options PADLOCK_RNG/RDRAND_RNG/etc..,
- * this event handler will do nothing, since the random
- * driver-specific handlers are loaded after these HW
- * consumers, and hence hasn't yet registered for this event.
- *
- * In case where both the random driver and RNG's are built
- * as seperate modules, random.ko is loaded prior to *_rng.ko's
- * (by dependency). This event handler is there to delay
- * creation of /dev/{u,}random and attachment of this *_rng.ko.
- */
- EVENTHANDLER_INVOKE(random_adaptor_attach, &random_context);
- return (0);
- }
-
- return (EINVAL);
-}
-
-RANDOM_ADAPTOR_MODULE(RANDOM_MODULE_NAME, randomdev_modevent, 1);
diff --git a/sys/dev/random/randomdev_soft.h b/sys/dev/random/randomdev_soft.h
index cbee779..e814de6 100644
--- a/sys/dev/random/randomdev_soft.h
+++ b/sys/dev/random/randomdev_soft.h
@@ -29,58 +29,11 @@
#ifndef SYS_DEV_RANDOM_RANDOMDEV_SOFT_H_INCLUDED
#define SYS_DEV_RANDOM_RANDOMDEV_SOFT_H_INCLUDED
-/* This header contains only those definitions that are global
- * and harvester-specific for the entropy processor
+/* This header contains only those definitions that are
+ * specific to the entropy processor
*/
-/* #define ENTROPYSOURCE nn entropy sources (actually classes)
- * This is properly defined in
- * an enum in sys/random.h
- */
-
-/* The ring size _MUST_ be a power of 2 */
-#define HARVEST_RING_SIZE 1024 /* harvest ring buffer size */
-#define HARVEST_RING_MASK (HARVEST_RING_SIZE - 1)
-
-#define HARVESTSIZE 16 /* max size of each harvested entropy unit */
-
-/* These are used to queue harvested packets of entropy. The entropy
- * buffer size is pretty arbitrary.
- */
-struct harvest {
- uintmax_t somecounter; /* fast counter for clock jitter */
- uint8_t entropy[HARVESTSIZE]; /* the harvested entropy */
- u_int size, bits; /* stats about the entropy */
- enum esource source; /* origin of the entropy */
- STAILQ_ENTRY(harvest) next; /* next item on the list */
-};
-
void randomdev_init(void);
void randomdev_deinit(void);
-void randomdev_init_harvester(void (*)(u_int64_t, const void *, u_int,
- u_int, enum esource), int (*)(void *, int));
-void randomdev_deinit_harvester(void);
-
-void random_set_wakeup_exit(void *);
-void random_process_event(struct harvest *event);
-void randomdev_unblock(void);
-
-extern struct mtx random_reseed_mtx;
-
-/* If this was C++, the macro below would be a template */
-#define RANDOM_CHECK_UINT(name, min, max) \
-static int \
-random_check_uint_##name(SYSCTL_HANDLER_ARGS) \
-{ \
- if (oidp->oid_arg1 != NULL) { \
- if (*(u_int *)(oidp->oid_arg1) <= (min)) \
- *(u_int *)(oidp->oid_arg1) = (min); \
- else if (*(u_int *)(oidp->oid_arg1) > (max)) \
- *(u_int *)(oidp->oid_arg1) = (max); \
- } \
- return (sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, \
- req)); \
-}
-
#endif
diff --git a/sys/dev/random/rwfile.c b/sys/dev/random/rwfile.c
deleted file mode 100644
index 9b38957..0000000
--- a/sys/dev/random/rwfile.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*-
- * Copyright (c) 2013 Mark R V Murray
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer
- * in this position and unchanged.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_random.h"
-
-#ifdef RANDOM_RWFILE
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/proc.h>
-#include <sys/namei.h>
-#include <sys/fcntl.h>
-#include <sys/vnode.h>
-
-#include <dev/random/rwfile.h>
-
-int
-randomdev_read_file(const char *filename, void *buf, size_t length)
-{
- struct nameidata nd;
- struct thread* td = curthread;
- int error;
- ssize_t resid;
- int flags;
-
- NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td);
- flags = FREAD;
- error = vn_open(&nd, &flags, 0, NULL);
- if (error == 0) {
- NDFREE(&nd, NDF_ONLY_PNBUF);
- if (nd.ni_vp->v_type != VREG)
- error = ENOEXEC;
- else
- error = vn_rdwr(UIO_READ, nd.ni_vp, buf, length, 0, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td);
- VOP_UNLOCK(nd.ni_vp, 0);
- vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
- }
-
- return (error);
-}
-
-int
-randomdev_write_file(const char *filename, void *buf, size_t length)
-{
- struct nameidata nd;
- struct thread* td = curthread;
- int error;
- ssize_t resid;
- int flags;
-
- NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td);
- flags = FWRITE | O_CREAT | O_TRUNC;
- error = vn_open(&nd, &flags, 0, NULL);
- if (error == 0) {
- NDFREE(&nd, NDF_ONLY_PNBUF);
- if (nd.ni_vp->v_type != VREG)
- error = ENOEXEC;
- else
- error = vn_rdwr(UIO_WRITE, nd.ni_vp, buf, length, 0, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td);
-
- VOP_UNLOCK(nd.ni_vp, 0);
- vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
- }
-
- return (error);
-}
-
-#endif
diff --git a/sys/dev/random/uint128.h b/sys/dev/random/uint128.h
new file mode 100644
index 0000000..b2cc1e0
--- /dev/null
+++ b/sys/dev/random/uint128.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2014 Mark R V Murray
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef SYS_DEV_RANDOM_UINT128_H_INCLUDED
+#define SYS_DEV_RANDOM_UINT128_H_INCLUDED
+
+/* This whole thing is a crock :-(
+ *
+ * Everyone knows you always need the __uint128_t types!
+ */
+
+#ifdef __SIZEOF_INT128__
+typedef __uint128_t uint128_t;
+#else
+typedef uint64_t uint128_t[2];
+#endif
+
+static __inline void
+uint128_clear(uint128_t *big_uint)
+{
+#ifdef __SIZEOF_INT128__
+ (*big_uint) = 0ULL;
+#else
+ (*big_uint)[0] = (*big_uint)[1] = 0UL;
+#endif
+}
+
+static __inline void
+uint128_increment(uint128_t *big_uint)
+{
+#ifdef __SIZEOF_INT128__
+ (*big_uint)++;
+#else
+ (*big_uint)[0]++;
+ if ((*big_uint)[0] == 0UL)
+ (*big_uint)[1]++;
+#endif
+}
+
+static __inline int
+uint128_is_zero(uint128_t big_uint)
+{
+#ifdef __SIZEOF_INT128__
+ return (big_uint == 0ULL);
+#else
+ return (big_uint[0] == 0UL && big_uint[1] == 0UL);
+#endif
+}
+
+#endif /* SYS_DEV_RANDOM_UINT128_H_INCLUDED */
diff --git a/sys/dev/random/unit_test.c b/sys/dev/random/unit_test.c
new file mode 100644
index 0000000..32b3363
--- /dev/null
+++ b/sys/dev/random/unit_test.c
@@ -0,0 +1,257 @@
+/*-
+ * Copyright (c) 2000-2013 Mark R V Murray
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ Build this by going:
+
+cc -g -O0 -pthread -DRANDOM_<alg> -DRANDOM_DEBUG -I../.. -lstdthreads -Wall \
+ unit_test.c \
+ yarrow.c \
+ fortuna.c \
+ hash.c \
+ ../../crypto/rijndael/rijndael-api-fst.c \
+ ../../crypto/rijndael/rijndael-alg-fst.c \
+ ../../crypto/sha2/sha2.c \
+ -o unit_test
+./unit_test
+
+Where <alg> is YARROW or FORTUNA.
+*/
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <threads.h>
+#include <unistd.h>
+
+#include "unit_test.h"
+
+#ifdef RANDOM_YARROW
+#include "dev/random/yarrow.h"
+#endif
+#ifdef RANDOM_FORTUNA
+#include "dev/random/fortuna.h"
+#endif
+
+#define NUM_THREADS 3
+
+static volatile int stopseeding = 0;
+
+void
+random_adaptor_unblock(void)
+{
+
+#if 0
+ if (mtx_trylock(&random_reseed_mtx) == thrd_busy)
+ printf("Mutex held. Good.\n");
+ else {
+ printf("Mutex not held. PANIC!!\n");
+ thrd_exit(0);
+ }
+#endif
+ printf("random: unblocking device.\n");
+}
+
+static int
+RunHarvester(void *arg __unused)
+{
+ int i, r;
+ struct harvest_event e;
+
+ for (i = 0; ; i++) {
+ if (stopseeding)
+ break;
+ if (i % 1000 == 0)
+ printf("Harvest: %d\n", i);
+ r = random()%10;
+ e.he_somecounter = i;
+ *((uint64_t *)e.he_entropy) = random();
+ e.he_size = 8;
+ e.he_bits = random()%4;
+ e.he_destination = i;
+ e.he_source = (i + 3)%7;
+ e.he_next = NULL;
+#ifdef RANDOM_YARROW
+ random_yarrow_process_event(&e);
+#endif
+#ifdef RANDOM_FORTUNA
+ random_fortuna_process_event(&e);
+#endif
+ usleep(r);
+ }
+
+ printf("Thread #0 ends\n");
+
+ thrd_exit(0);
+
+ return (0);
+}
+
+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) {
+#ifdef RANDOM_YARROW
+ random_yarrow_write(buf, i);
+#endif
+#ifdef RANDOM_FORTUNA
+ random_fortuna_write(buf, i);
+#endif
+ free(buf);
+ }
+ usleep(1000000);
+ }
+
+ printf("Thread #1 ends\n");
+
+ thrd_exit(0);
+
+ return (0);
+}
+
+static int
+ReadCSPRNG(void *threadid)
+{
+ size_t tid;
+ uint8_t *buf;
+ int i;
+
+ tid = (size_t)threadid;
+ printf("Thread #%zd starts\n", tid);
+
+#ifdef RANDOM_YARROW
+ while (!random_yarrow_seeded())
+#endif
+#ifdef RANDOM_FORTUNA
+ while (!random_fortuna_seeded())
+#endif
+ {
+#ifdef RANDOM_YARROW
+ random_yarrow_read(NULL, 0);
+ random_yarrow_read(NULL, 1);
+#endif
+#ifdef RANDOM_FORTUNA
+ random_fortuna_read(NULL, 0);
+ random_fortuna_read(NULL, 1);
+#endif
+ usleep(100);
+ }
+
+ for (i = 0; i < 100000; i++) {
+ buf = malloc(i);
+ if (i % 1000 == 0)
+ printf("Thread read %zd - %d %p\n", tid, i, buf);
+ if (buf != NULL) {
+#ifdef RANDOM_YARROW
+ random_yarrow_read(NULL, 0);
+ random_yarrow_read(buf, i);
+ random_yarrow_read(NULL, 1);
+#endif
+#ifdef RANDOM_FORTUNA
+ random_fortuna_read(NULL, 0);
+ random_fortuna_read(buf, i);
+ random_fortuna_read(NULL, 1);
+#endif
+#if 0
+ {
+ int j;
+
+ for (j = 0; j < i; j++) {
+ printf(" %02X", buf[j]);
+ if (j % 32 == 31 || j == i - 1)
+ printf("\n");
+ }
+ }
+#endif
+ free(buf);
+ }
+ usleep(100);
+ }
+
+ printf("Thread #%zd ends\n", tid);
+
+ thrd_exit(0);
+
+ return (0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ thrd_t threads[NUM_THREADS];
+ int rc;
+ long t;
+
+#ifdef RANDOM_YARROW
+ random_yarrow_init_alg();
+#endif
+#ifdef RANDOM_FORTUNA
+ random_fortuna_init_alg();
+#endif
+
+ 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)), t);
+ if (rc != thrd_success) {
+ printf("ERROR; return code from thrd_create() is %d\n", rc);
+ exit(-1);
+ }
+ }
+
+ for (t = 2; t < NUM_THREADS; t++)
+ thrd_join(threads[t], &rc);
+
+ stopseeding = 1;
+
+ thrd_join(threads[1], &rc);
+ thrd_join(threads[0], &rc);
+
+#ifdef RANDOM_YARROW
+ random_yarrow_deinit_alg();
+#endif
+#ifdef RANDOM_FORTUNA
+ random_fortuna_deinit_alg();
+#endif
+
+ /* Last thing that main() should do */
+ thrd_exit(0);
+
+ return (0);
+}
diff --git a/sys/dev/random/unit_test.h b/sys/dev/random/unit_test.h
new file mode 100644
index 0000000..9fc0931
--- /dev/null
+++ b/sys/dev/random/unit_test.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2013 Mark R V Murray
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+
+#ifndef UNIT_TEST_H_INCLUDED
+#define UNIT_TEST_H_INCLUDED
+
+void random_adaptor_unblock(void);
+
+static __inline uint64_t
+get_cyclecount(void)
+{
+
+ /* Shaddup! */
+ return (4ULL);
+}
+
+// #define PAGE_SIZE 4096
+#define HARVESTSIZE 16
+
+enum random_entropy_source {
+ RANDOM_START = 0,
+ RANDOM_CACHED = 0,
+ ENTROPYSOURCE = 32
+};
+
+struct harvest_event {
+ uintmax_t he_somecounter; /* fast counter for clock jitter */
+ uint8_t he_entropy[HARVESTSIZE];/* some harvested entropy */
+ u_int he_size; /* harvested entropy byte count */
+ u_int he_bits; /* stats about the entropy */
+ u_int he_destination; /* destination pool of this entropy */
+ enum random_entropy_source he_source; /* origin of the entropy */
+ void * he_next; /* next item on the list */
+};
+
+struct sysctl_ctx_list;
+
+#define CTASSERT(x) _Static_assert(x, "compile-time assertion failed")
+#define KASSERT(exp,msg) do { \
+ if (!(exp)) { \
+ printf msg; \
+ exit(0); \
+ } \
+} while (0)
+
+#endif /* UNIT_TEST_H_INCLUDED */
diff --git a/sys/dev/random/yarrow.c b/sys/dev/random/yarrow.c
index 1cfa373..a8da20a 100644
--- a/sys/dev/random/yarrow.c
+++ b/sys/dev/random/yarrow.c
@@ -28,6 +28,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#ifdef _KERNEL
#include "opt_random.h"
#include <sys/param.h>
@@ -39,197 +40,280 @@ __FBSDID("$FreeBSD$");
#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_adaptors.h>
-#include <dev/random/randomdev_soft.h>
+#include <dev/random/random_harvestq.h>
+#include <dev/random/uint128.h>
+#include <dev/random/yarrow.h>
+#else /* !_KERNEL */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <threads.h>
+
+#include "unit_test.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/uint128.h>
#include <dev/random/yarrow.h>
+#endif /* _KERNEL */
+
+#if !defined(RANDOM_YARROW) && !defined(RANDOM_FORTUNA)
+#define RANDOM_YARROW
+#elif defined(RANDOM_YARROW) && defined(RANDOM_FORTUNA)
+#error "Must define either RANDOM_YARROW or RANDOM_FORTUNA"
+#endif
+
+#if defined(RANDOM_YARROW)
#define TIMEBIN 16 /* max value for Pt/t */
#define FAST 0
#define SLOW 1
+/* This algorithm (and code) presumes that KEYSIZE is twice as large as BLOCKSIZE */
+CTASSERT(BLOCKSIZE == sizeof(uint128_t));
+CTASSERT(KEYSIZE == 2*BLOCKSIZE);
+
/* This is the beastie that needs protecting. It contains all of the
* state that we are excited about.
* Exactly one is instantiated.
*/
-static struct random_state {
+static struct yarrow_state {
union {
uint8_t byte[BLOCKSIZE];
- uint64_t qword[BLOCKSIZE/sizeof(uint64_t)];
- } counter; /* C */
- struct randomdev_key key; /* K */
- u_int gengateinterval; /* Pg */
- u_int bins; /* Pt/t */
- u_int outputblocks; /* count output blocks for gates */
- u_int slowoverthresh; /* slow pool overthreshhold reseed count */
+ uint128_t whole;
+ } counter; /* C */
+ struct randomdev_key key; /* K */
+ u_int gengateinterval; /* Pg */
+ u_int bins; /* Pt/t */
+ u_int outputblocks; /* count output blocks for gates */
+ u_int slowoverthresh; /* slow pool overthreshhold reseed count */
struct pool {
struct source {
u_int bits; /* estimated bits of entropy */
- } source[ENTROPYSOURCE];
- u_int thresh; /* pool reseed threshhold */
+ } source[ENTROPYSOURCE];/* ... per source */
+ u_int thresh; /* pool reseed threshhold */
struct randomdev_hash hash; /* accumulated entropy */
- } pool[2]; /* pool[0] is fast, pool[1] is slow */
- u_int which; /* toggle - sets the current insertion pool */
-} random_state;
+ } pool[2]; /* pool[0] is fast, pool[1] is slow */
+ int seeded;
+
+ struct start_cache {
+ uint8_t junk[KEYSIZE];
+ struct randomdev_hash hash;
+ } start_cache;
+} yarrow_state;
+/* The random_reseed_mtx mutex protects seeding and polling/blocking. */
+static mtx_t random_reseed_mtx;
+
+#ifdef _KERNEL
+static struct sysctl_ctx_list random_clist;
RANDOM_CHECK_UINT(gengateinterval, 4, 64);
RANDOM_CHECK_UINT(bins, 2, 16);
RANDOM_CHECK_UINT(fastthresh, (BLOCKSIZE*8)/4, (BLOCKSIZE*8)); /* Bit counts */
RANDOM_CHECK_UINT(slowthresh, (BLOCKSIZE*8)/4, (BLOCKSIZE*8)); /* Bit counts */
RANDOM_CHECK_UINT(slowoverthresh, 1, 5);
+#else /* !_KERNEL */
+static u_int harvest_destination[ENTROPYSOURCE];
+#endif /* _KERNEL */
static void generator_gate(void);
static void reseed(u_int);
-/* The reseed thread mutex */
-struct mtx random_reseed_mtx;
-
-/* 128-bit C = 0 */
-/* Nothing to see here, folks, just an ugly mess. */
-static void
-clear_counter(void)
-{
- random_state.counter.qword[0] = 0UL;
- random_state.counter.qword[1] = 0UL;
-}
-
-/* 128-bit C = C + 1 */
-/* Nothing to see here, folks, just an ugly mess. */
-/* TODO: Make a Galois counter instead? */
-static void
-increment_counter(void)
-{
- random_state.counter.qword[0]++;
- if (!random_state.counter.qword[0])
- random_state.counter.qword[1]++;
-}
-
-/* Process a single stochastic event off the harvest queue */
void
-random_process_event(struct harvest *event)
+random_yarrow_init_alg(void)
{
- u_int pl, overthreshhold[2];
- struct source *source;
- enum esource src;
-
-#if 0
- /* Do this better with DTrace */
- {
- int i;
-
- printf("Harvest:%16jX ", event->somecounter);
- for (i = 0; i < event->size; i++)
- printf("%02X", event->entropy[i]);
- for (; i < 16; i++)
- printf(" ");
- printf(" %2d %2d %02X\n", event->size, event->bits, event->source);
- }
-#endif
-
- /* Accumulate the event into the appropriate pool */
- pl = random_state.which;
- source = &random_state.pool[pl].source[event->source];
- randomdev_hash_iterate(&random_state.pool[pl].hash, event,
- sizeof(*event));
- source->bits += event->bits;
-
- /* Count the over-threshold sources in each pool */
- for (pl = 0; pl < 2; pl++) {
- overthreshhold[pl] = 0;
- for (src = RANDOM_START; src < ENTROPYSOURCE; src++) {
- if (random_state.pool[pl].source[src].bits
- > random_state.pool[pl].thresh)
- overthreshhold[pl]++;
- }
- }
-
- /* if any fast source over threshhold, reseed */
- if (overthreshhold[FAST])
- reseed(FAST);
+ int i, j;
+#ifdef _KERNEL
+ struct sysctl_oid *random_yarrow_o;
+#endif /* _KERNEL */
- /* if enough slow sources are over threshhold, reseed */
- if (overthreshhold[SLOW] >= random_state.slowoverthresh)
- reseed(SLOW);
+ memset(yarrow_state.start_cache.junk, 0, KEYSIZE);
+ randomdev_hash_init(&yarrow_state.start_cache.hash);
- /* Invert the fast/slow pool selector bit */
- random_state.which = !random_state.which;
-}
+ /* Set up the lock for the reseed/gate state */
+#ifdef _KERNEL
+ mtx_init(&random_reseed_mtx, "reseed mutex", NULL, MTX_DEF);
+#else /* !_KERNEL */
+ mtx_init(&random_reseed_mtx, mtx_plain);
+#endif /* _KERNEL */
-void
-random_yarrow_init_alg(struct sysctl_ctx_list *clist)
-{
- int i;
- struct sysctl_oid *random_yarrow_o;
+ /* Start unseeded, therefore blocked. */
+ yarrow_state.seeded = 0;
+#ifdef _KERNEL
/* Yarrow parameters. Do not adjust these unless you have
* have a very good clue about what they do!
*/
- random_yarrow_o = SYSCTL_ADD_NODE(clist,
+ random_yarrow_o = SYSCTL_ADD_NODE(&random_clist,
SYSCTL_STATIC_CHILDREN(_kern_random),
OID_AUTO, "yarrow", CTLFLAG_RW, 0,
"Yarrow Parameters");
- SYSCTL_ADD_PROC(clist,
+ SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
"gengateinterval", CTLTYPE_INT|CTLFLAG_RW,
- &random_state.gengateinterval, 10,
+ &yarrow_state.gengateinterval, 10,
random_check_uint_gengateinterval, "I",
"Generation gate interval");
- SYSCTL_ADD_PROC(clist,
+ SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
"bins", CTLTYPE_INT|CTLFLAG_RW,
- &random_state.bins, 10,
+ &yarrow_state.bins, 10,
random_check_uint_bins, "I",
"Execution time tuner");
- SYSCTL_ADD_PROC(clist,
+ SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
"fastthresh", CTLTYPE_INT|CTLFLAG_RW,
- &random_state.pool[0].thresh, (3*(BLOCKSIZE*8))/4,
+ &yarrow_state.pool[0].thresh, (3*(BLOCKSIZE*8))/4,
random_check_uint_fastthresh, "I",
"Fast reseed threshold");
- SYSCTL_ADD_PROC(clist,
+ SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
"slowthresh", CTLTYPE_INT|CTLFLAG_RW,
- &random_state.pool[1].thresh, (BLOCKSIZE*8),
+ &yarrow_state.pool[1].thresh, (BLOCKSIZE*8),
random_check_uint_slowthresh, "I",
"Slow reseed threshold");
- SYSCTL_ADD_PROC(clist,
+ SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
"slowoverthresh", CTLTYPE_INT|CTLFLAG_RW,
- &random_state.slowoverthresh, 2,
+ &yarrow_state.slowoverthresh, 2,
random_check_uint_slowoverthresh, "I",
"Slow over-threshold reseed");
+#endif /* _KERNEL */
- random_state.gengateinterval = 10;
- random_state.bins = 10;
- random_state.pool[0].thresh = (3*(BLOCKSIZE*8))/4;
- random_state.pool[1].thresh = (BLOCKSIZE*8);
- random_state.slowoverthresh = 2;
- random_state.which = FAST;
+ yarrow_state.gengateinterval = 10;
+ yarrow_state.bins = 10;
+ yarrow_state.pool[FAST].thresh = (3*(BLOCKSIZE*8))/4;
+ yarrow_state.pool[SLOW].thresh = (BLOCKSIZE*8);
+ yarrow_state.slowoverthresh = 2;
+
+ /* Ensure that the first time we read, we are gated. */
+ yarrow_state.outputblocks = yarrow_state.gengateinterval;
/* Initialise the fast and slow entropy pools */
- for (i = 0; i < 2; i++)
- randomdev_hash_init(&random_state.pool[i].hash);
+ for (i = FAST; i <= SLOW; i++) {
+ randomdev_hash_init(&yarrow_state.pool[i].hash);
+ for (j = RANDOM_START; j < ENTROPYSOURCE; j++)
+ yarrow_state.pool[i].source[j].bits = 0U;
+ }
/* Clear the counter */
- clear_counter();
-
- /* Set up a lock for the reseed process */
- mtx_init(&random_reseed_mtx, "Yarrow reseed", NULL, MTX_DEF);
+ uint128_clear(&yarrow_state.counter.whole);
}
void
random_yarrow_deinit_alg(void)
{
+
mtx_destroy(&random_reseed_mtx);
+ memset(&yarrow_state, 0, sizeof(yarrow_state));
+
+#ifdef _KERNEL
+ sysctl_ctx_free(&random_clist);
+#endif
+}
+
+static __inline void
+random_yarrow_post_insert(void)
+{
+ u_int pl, overthreshhold[2];
+ enum random_entropy_source src;
+
+#ifdef _KERNEL
+ mtx_assert(&random_reseed_mtx, MA_OWNED);
+#endif
+ /* Count the over-threshold sources in each pool */
+ for (pl = 0; pl < 2; pl++) {
+ overthreshhold[pl] = 0;
+ for (src = RANDOM_START; src < ENTROPYSOURCE; src++) {
+ if (yarrow_state.pool[pl].source[src].bits > yarrow_state.pool[pl].thresh)
+ overthreshhold[pl]++;
+ }
+ }
+
+ /* If enough slow sources are over threshhold, then slow reseed
+ * else if any fast source over threshhold, then fast reseed.
+ */
+ if (overthreshhold[SLOW] >= yarrow_state.slowoverthresh)
+ reseed(SLOW);
+ else if (overthreshhold[FAST] > 0 && yarrow_state.seeded)
+ reseed(FAST);
+}
+
+/* Process a single stochastic event off the harvest queue */
+void
+random_yarrow_process_event(struct harvest_event *event)
+{
+ u_int pl;
+
+ mtx_lock(&random_reseed_mtx);
+
+ /* Accumulate the event into the appropriate pool
+ * where each event carries the destination information.
+ * We lock against pool state modification which can happen
+ * during accumulation/reseeding and reading/regating
+ */
+ pl = event->he_destination % 2;
+ randomdev_hash_iterate(&yarrow_state.pool[pl].hash, event, sizeof(*event));
+ yarrow_state.pool[pl].source[event->he_source].bits += event->he_bits;
+
+ random_yarrow_post_insert();
+
+ mtx_unlock(&random_reseed_mtx);
+}
+
+/* Process a block of data suspected to be slightly stochastic */
+static void
+random_yarrow_process_buffer(uint8_t *buf, u_int length)
+{
+ static struct harvest_event event;
+ u_int i, pl;
+
+ /* Accumulate the data into the appropriate pools
+ * where each event carries the destination information.
+ * We lock against pool state modification which can happen
+ * during accumulation/reseeding and reading/regating
+ */
+ memset(event.he_entropy + sizeof(uint32_t), 0, HARVESTSIZE - sizeof(uint32_t));
+ for (i = 0; i < length/sizeof(uint32_t); i++) {
+ event.he_somecounter = get_cyclecount();
+ event.he_bits = 0; /* Fake */
+ event.he_source = RANDOM_CACHED;
+ event.he_destination = harvest_destination[RANDOM_CACHED]++;
+ event.he_size = sizeof(uint32_t);
+ *((uint32_t *)event.he_entropy) = *((uint32_t *)buf + i);
+
+ /* Do the actual entropy insertion */
+ pl = event.he_destination % 2;
+ randomdev_hash_iterate(&yarrow_state.pool[pl].hash, &event, sizeof(event));
+#ifdef DONT_DO_THIS_HERE
+ /* Don't do this here - do it in bulk at the end */
+ yarrow_state.pool[pl].source[RANDOM_CACHED].bits += bits;
+#endif
+ }
+ for (pl = FAST; pl <= SLOW; pl++)
+ yarrow_state.pool[pl].source[RANDOM_CACHED].bits += (length >> 4);
+
+ random_yarrow_post_insert();
}
static void
@@ -239,45 +323,60 @@ reseed(u_int fastslow)
* structures static.
*/
static uint8_t v[TIMEBIN][KEYSIZE]; /* v[i] */
+ static uint8_t hash[KEYSIZE]; /* h' */
+ static uint8_t temp[KEYSIZE];
static struct randomdev_hash context;
- uint8_t hash[KEYSIZE]; /* h' */
- uint8_t temp[KEYSIZE];
u_int i;
- enum esource j;
+ enum random_entropy_source j;
-#if 0
- printf("Yarrow: %s reseed\n", fastslow == FAST ? "fast" : "slow");
-#endif
+ KASSERT(yarrow_state.pool[FAST].thresh > 0, ("random: Yarrow fast threshold = 0"));
+ KASSERT(yarrow_state.pool[SLOW].thresh > 0, ("random: Yarrow slow threshold = 0"));
- /* The reseed task must not be jumped on */
- mtx_lock(&random_reseed_mtx);
+#ifdef RANDOM_DEBUG
+#ifdef RANDOM_DEBUG_VERBOSE
+ printf("random: %s %s\n", __func__, (fastslow == FAST ? "FAST" : "SLOW"));
+#endif
+ if (!yarrow_state.seeded) {
+ printf("random: %s - fast - thresh %d,1 - ", __func__, yarrow_state.pool[FAST].thresh);
+ for (i = RANDOM_START; i < ENTROPYSOURCE; i++)
+ printf(" %d", yarrow_state.pool[FAST].source[i].bits);
+ printf("\n");
+ printf("random: %s - slow - thresh %d,%d - ", __func__, yarrow_state.pool[SLOW].thresh, yarrow_state.slowoverthresh);
+ for (i = RANDOM_START; i < ENTROPYSOURCE; i++)
+ printf(" %d", yarrow_state.pool[SLOW].source[i].bits);
+ printf("\n");
+ }
+#endif
+#ifdef _KERNEL
+ mtx_assert(&random_reseed_mtx, MA_OWNED);
+#endif
/* 1. Hash the accumulated entropy into v[0] */
randomdev_hash_init(&context);
/* Feed the slow pool hash in if slow */
- if (fastslow == SLOW)
- randomdev_hash_iterate(&context,
- &random_state.pool[SLOW].hash,
- sizeof(struct randomdev_hash));
- randomdev_hash_iterate(&context,
- &random_state.pool[FAST].hash, sizeof(struct randomdev_hash));
+ if (fastslow == SLOW) {
+ randomdev_hash_finish(&yarrow_state.pool[SLOW].hash, temp);
+ randomdev_hash_iterate(&context, temp, sizeof(temp));
+ }
+ randomdev_hash_finish(&yarrow_state.pool[FAST].hash, temp);
+ randomdev_hash_iterate(&context, temp, sizeof(temp));
randomdev_hash_finish(&context, v[0]);
/* 2. Compute hash values for all v. _Supposed_ to be computationally
* intensive.
*/
- if (random_state.bins > TIMEBIN)
- random_state.bins = TIMEBIN;
- for (i = 1; i < random_state.bins; i++) {
+ if (yarrow_state.bins > TIMEBIN)
+ yarrow_state.bins = TIMEBIN;
+ for (i = 1; i < yarrow_state.bins; i++) {
randomdev_hash_init(&context);
/* v[i] #= h(v[i - 1]) */
randomdev_hash_iterate(&context, v[i - 1], KEYSIZE);
/* v[i] #= h(v[0]) */
randomdev_hash_iterate(&context, v[0], KEYSIZE);
/* v[i] #= h(i) */
- randomdev_hash_iterate(&context, &i, sizeof(u_int));
+ randomdev_hash_iterate(&context, &i, sizeof(i));
/* Return the hashval */
randomdev_hash_finish(&context, v[i]);
}
@@ -287,98 +386,107 @@ reseed(u_int fastslow)
*/
randomdev_hash_init(&context);
- randomdev_hash_iterate(&context, &random_state.key, KEYSIZE);
- for (i = 1; i < random_state.bins; i++)
- randomdev_hash_iterate(&context, &v[i], KEYSIZE);
+ randomdev_hash_iterate(&context, &yarrow_state.key, KEYSIZE);
+ for (i = 1; i < yarrow_state.bins; i++)
+ randomdev_hash_iterate(&context, v[i], KEYSIZE);
randomdev_hash_finish(&context, temp);
- randomdev_encrypt_init(&random_state.key, temp);
+ randomdev_encrypt_init(&yarrow_state.key, temp);
/* 4. Recompute the counter */
- clear_counter();
- randomdev_encrypt(&random_state.key, random_state.counter.byte, temp, BLOCKSIZE);
- memcpy(random_state.counter.byte, temp, BLOCKSIZE);
+ uint128_clear(&yarrow_state.counter.whole);
+ randomdev_encrypt(&yarrow_state.key, yarrow_state.counter.byte, temp, BLOCKSIZE);
+ memcpy(yarrow_state.counter.byte, temp, BLOCKSIZE);
/* 5. Reset entropy estimate accumulators to zero */
for (i = 0; i <= fastslow; i++)
for (j = RANDOM_START; j < ENTROPYSOURCE; j++)
- random_state.pool[i].source[j].bits = 0;
+ yarrow_state.pool[i].source[j].bits = 0;
/* 6. Wipe memory of intermediate values */
- memset((void *)v, 0, sizeof(v));
- memset((void *)temp, 0, sizeof(temp));
- memset((void *)hash, 0, sizeof(hash));
+ memset(v, 0, sizeof(v));
+ memset(temp, 0, sizeof(temp));
+ memset(hash, 0, sizeof(hash));
+ memset(&context, 0, sizeof(context));
+#ifdef RANDOM_RWFILE_WRITE_IS_OK /* Not defined so writes ain't gonna happen */
/* 7. Dump to seed file */
- /* XXX Not done here yet */
- /* Unblock the device if it was blocked due to being unseeded */
- randomdev_unblock();
+ /* This pseudo-code is documentation. Please leave it alone. */
+ seed_file = "<some file>";
+ error = randomdev_write_file(seed_file, <generated entropy>, PAGE_SIZE);
+ if (error == 0)
+ printf("random: entropy seed file '%s' successfully written\n", seed_file);
+#endif
- /* Release the reseed mutex */
- mtx_unlock(&random_reseed_mtx);
+ /* Unblock the device if it was blocked due to being unseeded */
+ if (!yarrow_state.seeded) {
+ yarrow_state.seeded = 1;
+ random_adaptor_unblock();
+ }
}
/* Internal function to return processed entropy from the PRNG */
-int
-random_yarrow_read(void *buf, int count)
+void
+random_yarrow_read(uint8_t *buf, u_int bytecount)
{
- static int cur = 0;
- static int gate = 1;
- static uint8_t genval[KEYSIZE];
- size_t tomove;
- int i;
- int retval;
+ u_int blockcount, i;
- /* Check for final read request */
- if (buf == NULL && count == 0)
- return (0);
+ /* Check for initial/final read requests */
+ if (buf == NULL)
+ return;
/* The reseed task must not be jumped on */
mtx_lock(&random_reseed_mtx);
- if (gate) {
- generator_gate();
- random_state.outputblocks = 0;
- gate = 0;
- }
- if (count > 0 && (size_t)count >= BLOCKSIZE) {
- retval = 0;
- for (i = 0; i < count; i += BLOCKSIZE) {
- increment_counter();
- randomdev_encrypt(&random_state.key, random_state.counter.byte, genval, BLOCKSIZE);
- tomove = MIN(count - i, BLOCKSIZE);
- memcpy((char *)buf + i, genval, tomove);
- if (++random_state.outputblocks >= random_state.gengateinterval) {
- generator_gate();
- random_state.outputblocks = 0;
- }
- retval += (int)tomove;
- cur = 0;
+ blockcount = (bytecount + BLOCKSIZE - 1)/BLOCKSIZE;
+ for (i = 0; i < blockcount; i++) {
+ if (yarrow_state.outputblocks++ >= yarrow_state.gengateinterval) {
+ generator_gate();
+ yarrow_state.outputblocks = 0;
}
+ uint128_increment(&yarrow_state.counter.whole);
+ randomdev_encrypt(&yarrow_state.key, yarrow_state.counter.byte, buf, BLOCKSIZE);
+ buf += BLOCKSIZE;
}
- else {
- if (!cur) {
- increment_counter();
- randomdev_encrypt(&random_state.key, random_state.counter.byte, genval, BLOCKSIZE);
- memcpy(buf, genval, (size_t)count);
- cur = BLOCKSIZE - count;
- if (++random_state.outputblocks >= random_state.gengateinterval) {
- generator_gate();
- random_state.outputblocks = 0;
- }
- retval = count;
- }
- else {
- retval = MIN(cur, count);
- memcpy(buf, &genval[BLOCKSIZE - cur], (size_t)retval);
- cur -= retval;
- }
+
+ mtx_unlock(&random_reseed_mtx);
+}
+
+/* Internal function to hand external entropy to the PRNG */
+void
+random_yarrow_write(uint8_t *buf, u_int count)
+{
+ uintmax_t timestamp;
+
+ /* We must be locked for all this as plenty of state gets messed with */
+ mtx_lock(&random_reseed_mtx);
+
+ timestamp = get_cyclecount();
+ randomdev_hash_iterate(&yarrow_state.start_cache.hash, &timestamp, sizeof(timestamp));
+ randomdev_hash_iterate(&yarrow_state.start_cache.hash, buf, count);
+ timestamp = get_cyclecount();
+ randomdev_hash_iterate(&yarrow_state.start_cache.hash, &timestamp, sizeof(timestamp));
+ randomdev_hash_finish(&yarrow_state.start_cache.hash, yarrow_state.start_cache.junk);
+ randomdev_hash_init(&yarrow_state.start_cache.hash);
+
+#ifdef RANDOM_DEBUG_VERBOSE
+ {
+ int i;
+
+ printf("random: %s - ", __func__);
+ for (i = 0; i < KEYSIZE; i++)
+ printf("%02X", yarrow_state.start_cache.junk[i]);
+ printf("\n");
}
+#endif
+
+ random_yarrow_process_buffer(yarrow_state.start_cache.junk, KEYSIZE);
+ memset(yarrow_state.start_cache.junk, 0, KEYSIZE);
+
mtx_unlock(&random_reseed_mtx);
- return (retval);
}
static void
@@ -388,29 +496,26 @@ generator_gate(void)
uint8_t temp[KEYSIZE];
for (i = 0; i < KEYSIZE; i += BLOCKSIZE) {
- increment_counter();
- randomdev_encrypt(&random_state.key, random_state.counter.byte, temp + i, BLOCKSIZE);
+ uint128_increment(&yarrow_state.counter.whole);
+ randomdev_encrypt(&yarrow_state.key, yarrow_state.counter.byte, temp + i, BLOCKSIZE);
}
- randomdev_encrypt_init(&random_state.key, temp);
- memset((void *)temp, 0, KEYSIZE);
+ randomdev_encrypt_init(&yarrow_state.key, temp);
+ memset(temp, 0, KEYSIZE);
}
-/* Helper routine to perform explicit reseeds */
void
random_yarrow_reseed(void)
{
-#ifdef RANDOM_DEBUG
- int i;
-
- printf("%s(): fast:", __func__);
- for (i = RANDOM_START; i < ENTROPYSOURCE; ++i)
- printf(" %d", random_state.pool[FAST].source[i].bits);
- printf("\n");
- printf("%s(): slow:", __func__);
- for (i = RANDOM_START; i < ENTROPYSOURCE; ++i)
- printf(" %d", random_state.pool[SLOW].source[i].bits);
- printf("\n");
-#endif
+
reseed(SLOW);
}
+
+int
+random_yarrow_seeded(void)
+{
+
+ return (yarrow_state.seeded);
+}
+
+#endif /* RANDOM_YARROW */
diff --git a/sys/dev/random/yarrow.h b/sys/dev/random/yarrow.h
index f32313e..9ba0b4e 100644
--- a/sys/dev/random/yarrow.h
+++ b/sys/dev/random/yarrow.h
@@ -29,9 +29,16 @@
#ifndef SYS_DEV_RANDOM_YARROW_H_INCLUDED
#define SYS_DEV_RANDOM_YARROW_H_INCLUDED
-void random_yarrow_init_alg(struct sysctl_ctx_list *);
+#ifdef _KERNEL
+typedef struct mtx mtx_t;
+#endif
+
+void random_yarrow_init_alg(void);
void random_yarrow_deinit_alg(void);
-int random_yarrow_read(void *, int);
+void random_yarrow_read(uint8_t *, u_int);
+void random_yarrow_write(uint8_t *, u_int);
void random_yarrow_reseed(void);
+int random_yarrow_seeded(void);
+void random_yarrow_process_event(struct harvest_event *event);
#endif
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index 9faea00..9246904 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -853,4 +853,4 @@ kick_init(const void *udata __unused)
sched_add(td, SRQ_BORING);
thread_unlock(td);
}
-SYSINIT(kickinit, SI_SUB_KTHREAD_INIT, SI_ORDER_FIRST, kick_init, NULL);
+SYSINIT(kickinit, SI_SUB_KTHREAD_INIT, SI_ORDER_MIDDLE, kick_init, NULL);
diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c
index a8d9f1a..7a5d936 100644
--- a/sys/kern/kern_intr.c
+++ b/sys/kern/kern_intr.c
@@ -885,13 +885,10 @@ intr_event_schedule_thread(struct intr_event *ie)
* If any of the handlers for this ithread claim to be good
* sources of entropy, then gather some.
*/
- if (harvest.interrupt && ie->ie_flags & IE_ENTROPY) {
- CTR3(KTR_INTR, "%s: pid %d (%s) gathering entropy", __func__,
- p->p_pid, td->td_name);
+ if (ie->ie_flags & IE_ENTROPY) {
entropy.event = (uintptr_t)ie;
entropy.td = ctd;
- random_harvest(&entropy, sizeof(entropy), 2,
- RANDOM_INTERRUPT);
+ random_harvest(&entropy, sizeof(entropy), 2, RANDOM_INTERRUPT);
}
KASSERT(p != NULL, ("ithread %s has no process", ie->ie_name));
@@ -1039,13 +1036,10 @@ intr_event_schedule_thread(struct intr_event *ie, struct intr_thread *it)
* If any of the handlers for this ithread claim to be good
* sources of entropy, then gather some.
*/
- if (harvest.interrupt && ie->ie_flags & IE_ENTROPY) {
- CTR3(KTR_INTR, "%s: pid %d (%s) gathering entropy", __func__,
- p->p_pid, td->td_name);
+ if (ie->ie_flags & IE_ENTROPY) {
entropy.event = (uintptr_t)ie;
entropy.td = ctd;
- random_harvest(&entropy, sizeof(entropy), 2,
- RANDOM_INTERRUPT);
+ random_harvest(&entropy, sizeof(entropy), 2, RANDOM_INTERRUPT);
}
KASSERT(p != NULL, ("ithread %s has no process", ie->ie_name));
@@ -1130,14 +1124,9 @@ swi_sched(void *cookie, int flags)
CTR3(KTR_INTR, "swi_sched: %s %s need=%d", ie->ie_name, ih->ih_name,
ih->ih_need);
- if (harvest.swi) {
- CTR2(KTR_INTR, "swi_sched: pid %d (%s) gathering entropy",
- curproc->p_pid, curthread->td_name);
- entropy.event = (uintptr_t)ih;
- entropy.td = curthread;
- random_harvest(&entropy, sizeof(entropy), 1,
- RANDOM_SWI);
- }
+ entropy.event = (uintptr_t)ih;
+ entropy.td = curthread;
+ random_harvest(&entropy, sizeof(entropy), 1, RANDOM_SWI);
/*
* Set ih_need for this handler so that if the ithread is already
diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c
index 31ad45e..51d7ca6 100644
--- a/sys/kern/subr_bus.c
+++ b/sys/kern/subr_bus.c
@@ -2851,7 +2851,7 @@ device_attach(device_t dev)
* need to be adjusted on other platforms.
*/
#ifdef RANDOM_DEBUG
- printf("%s(): feeding %d bit(s) of entropy from %s%d\n",
+ printf("random: %s(): feeding %d bit(s) of entropy from %s%d\n",
__func__, 4, dev->driver->name, dev->unit);
#endif
random_harvest(&attachtime, sizeof(attachtime), 4, RANDOM_ATTACH);
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 23e4753..fa956df 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -270,6 +270,7 @@ SUBDIR= \
${_opensolaris} \
oce \
${_padlock} \
+ ${_padlock_rng} \
patm \
${_pccard} \
${_pcfclock} \
@@ -297,6 +298,7 @@ SUBDIR= \
${_random} \
rc4 \
${_rdma} \
+ ${_rdrand_rng} \
re \
reiserfs \
rl \
@@ -583,6 +585,8 @@ _nvram= nvram
_nxge= nxge
.if ${MK_CRYPT} != "no" || defined(ALL_MODULES)
_padlock= padlock
+_padlock_rng= padlock_rng
+_rdrand_rng= rdrand_rng
.endif
_s3= s3
_tpm= tpm
@@ -602,6 +606,17 @@ _x86bios= x86bios
_ixl= ixl
_ixlv= ixlv
_ntb= ntb
+_nvd= nvd
+_nvme= nvme
+_nvram= nvram
+_nxge= nxge
+.if ${MK_CDDL} != "no" || defined(ALL_MODULES)
+_opensolaris= opensolaris
+.endif
+.if ${MK_CRYPT} != "no" || defined(ALL_MODULES)
+_padlock= padlock
+.endif
+_pccard= pccard
_qlxge= qlxge
_qlxgb= qlxgb
_qlxgbe= qlxgbe
diff --git a/sys/modules/padlock_rng/Makefile b/sys/modules/padlock_rng/Makefile
new file mode 100644
index 0000000..25bf24f
--- /dev/null
+++ b/sys/modules/padlock_rng/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/random
+
+KMOD= padlock_rng
+SRCS= nehemiah.c
+SRCS+= bus_if.h device_if.h
+
+CFLAGS+= -I${.CURDIR}/../..
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/random/Makefile b/sys/modules/random/Makefile
index 6bf47f2..7d0370f 100644
--- a/sys/modules/random/Makefile
+++ b/sys/modules/random/Makefile
@@ -5,13 +5,9 @@
.PATH: ${.CURDIR}/../../crypto/sha2
KMOD= random
-SRCS= randomdev.c
-.if ${MACHINE} == "amd64" || ${MACHINE} == "i386"
-SRCS+= nehemiah.c
-SRCS+= ivy.c
-.endif
-SRCS+= randomdev_soft.c yarrow.c hash.c
-SRCS+= random_harvestq.c live_entropy_sources.c rwfile.c
+SRCS= randomdev_soft.c
+SRCS+= yarrow.c hash.c
+SRCS+= random_harvestq.c live_entropy_sources.c
SRCS+= rijndael-alg-fst.c rijndael-api-fst.c sha2.c sha256c.c
SRCS+= bus_if.h device_if.h vnode_if.h opt_cpu.h opt_random.h
diff --git a/sys/modules/rdrand_rng/Makefile b/sys/modules/rdrand_rng/Makefile
new file mode 100644
index 0000000..9d5adc3
--- /dev/null
+++ b/sys/modules/rdrand_rng/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/random
+
+KMOD= rdrand_rng
+SRCS= ivy.c
+SRCS+= bus_if.h device_if.h
+
+CFLAGS+= -I${.CURDIR}/../..
+
+.include <bsd.kmod.mk>
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 5f315ec..87e71b6 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -576,8 +576,7 @@ ether_input_internal(struct ifnet *ifp, struct mbuf *m)
m->m_flags |= M_PROMISC;
}
- if (harvest.ethernet)
- random_harvest(&(m->m_data), 12, 2, RANDOM_NET_ETHER);
+ random_harvest(&(m->m_data), 12, 2, RANDOM_NET_ETHER);
ether_demux(ifp, m);
CURVNET_RESTORE();
diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c
index 89af288..bb9de44 100644
--- a/sys/net/if_tun.c
+++ b/sys/net/if_tun.c
@@ -906,8 +906,7 @@ tunwrite(struct cdev *dev, struct uio *uio, int flag)
m_freem(m);
return (EAFNOSUPPORT);
}
- if (harvest.point_to_point)
- random_harvest(&(m->m_data), 12, 2, RANDOM_NET_TUN);
+ random_harvest(&(m->m_data), 12, 2, RANDOM_NET_TUN);
if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
CURVNET_SET(ifp->if_vnet);
diff --git a/sys/netgraph/ng_iface.c b/sys/netgraph/ng_iface.c
index 7326d3e..5aec8a3 100644
--- a/sys/netgraph/ng_iface.c
+++ b/sys/netgraph/ng_iface.c
@@ -758,8 +758,7 @@ ng_iface_rcvdata(hook_p hook, item_p item)
m_freem(m);
return (EAFNOSUPPORT);
}
- if (harvest.point_to_point)
- random_harvest(&(m->m_data), 12, 2, RANDOM_NET_NG);
+ random_harvest(&(m->m_data), 12, 2, RANDOM_NET_NG);
M_SETFIB(m, ifp->if_fib);
netisr_dispatch(isr, m);
return (0);
diff --git a/sys/sys/random.h b/sys/sys/random.h
index 8bb262a..2714625 100644
--- a/sys/sys/random.h
+++ b/sys/sys/random.h
@@ -34,12 +34,17 @@
int read_random(void *, int);
/*
- * Note: if you add or remove members of esource, remember to also update the
- * KASSERT regarding what valid members are in random_harvest_internal().
+ * Note: if you add or remove members of random_entropy_source, remember to also update the
+ * KASSERT regarding what valid members are in random_harvest_internal(), and remember the
+ * strings in the static array random_source_descr[] in random_harvestq.c.
+ *
+ * NOTE: complain loudly to markm@ or on the lists if this enum gets more than 32
+ * distinct values (0-31)! ENTROPYSOURCE may be == 32, but not > 32.
*/
-enum esource {
+enum random_entropy_source {
RANDOM_START = 0,
RANDOM_CACHED = 0,
+ /* Environmental sources */
RANDOM_ATTACH,
RANDOM_KEYBOARD,
RANDOM_MOUSE,
@@ -48,6 +53,9 @@ enum esource {
RANDOM_NET_NG,
RANDOM_INTERRUPT,
RANDOM_SWI,
+ RANDOM_UMA_ALLOC,
+ RANDOM_ENVIRONMENTAL_END, /* This one is wasted */
+ /* High-quality HW RNGs from here on. */
RANDOM_PURE_OCTEON,
RANDOM_PURE_SAFE,
RANDOM_PURE_GLXSB,
@@ -59,20 +67,7 @@ enum esource {
RANDOM_PURE_VIRTIO,
ENTROPYSOURCE
};
-void random_harvest(const void *, u_int, u_int, enum esource);
-
-/* Allow the sysadmin to select the broad category of
- * entropy types to harvest
- */
-struct harvest_select {
- int ethernet;
- int point_to_point;
- int interrupt;
- int swi;
- int namei;
-};
-
-extern struct harvest_select harvest;
+void random_harvest(const void *, u_int, u_int, enum random_entropy_source);
#endif /* _KERNEL */
diff --git a/sys/vm/uma_core.c b/sys/vm/uma_core.c
index 8527b09..50e66c0 100644
--- a/sys/vm/uma_core.c
+++ b/sys/vm/uma_core.c
@@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <sys/mutex.h>
#include <sys/proc.h>
+#include <sys/random.h>
#include <sys/rwlock.h>
#include <sys/sbuf.h>
#include <sys/sched.h>
@@ -2097,6 +2098,12 @@ uma_zalloc_arg(uma_zone_t zone, void *udata, int flags)
int lockfail;
int cpu;
+#if 0
+ /* XXX: FIX!! Do not enable this in CURRENT!! MarkM */
+ /* The entropy here is desirable, but the harvesting is expensive */
+ random_harvest(&(zone->uz_name), sizeof(void *), 1, RANDOM_UMA_ALLOC);
+#endif
+
/* This is the fast path allocation */
#ifdef UMA_DEBUG_ALLOC_1
printf("Allocating one item from %s(%p)\n", zone->uz_name, zone);
@@ -2127,6 +2134,11 @@ uma_zalloc_arg(uma_zone_t zone, void *udata, int flags)
zone->uz_fini(item, zone->uz_size);
return (NULL);
}
+#if 0
+ /* XXX: FIX!! Do not enable this in CURRENT!! MarkM */
+ /* The entropy here is desirable, but the harvesting is expensive */
+ random_harvest(&item, sizeof(void *), 1, RANDOM_UMA_ALLOC);
+#endif
return (item);
}
/* This is unfortunate but should not be fatal. */
@@ -2169,6 +2181,11 @@ zalloc_start:
#endif
if (flags & M_ZERO)
uma_zero_item(item, zone);
+#if 0
+ /* XXX: FIX!! Do not enable this in CURRENT!! MarkM */
+ /* The entropy here is desirable, but the harvesting is expensive */
+ random_harvest(&item, sizeof(void *), 1, RANDOM_UMA_ALLOC);
+#endif
return (item);
}
@@ -2289,6 +2306,11 @@ zalloc_start:
zalloc_item:
item = zone_alloc_item(zone, udata, flags);
+#if 0
+ /* XXX: FIX!! Do not enable this in CURRENT!! MarkM */
+ /* The entropy here is desirable, but the harvesting is expensive */
+ random_harvest(&item, sizeof(void *), 1, RANDOM_UMA_ALLOC);
+#endif
return (item);
}
@@ -2636,6 +2658,19 @@ uma_zfree_arg(uma_zone_t zone, void *item, void *udata)
int lockfail;
int cpu;
+#if 0
+ /* XXX: FIX!! Do not enable this in CURRENT!! MarkM */
+ /* The entropy here is desirable, but the harvesting is expensive */
+ struct entropy {
+ const void *uz_name;
+ const void *item;
+ } entropy;
+
+ entropy.uz_name = zone->uz_name;
+ entropy.item = item;
+ random_harvest(&entropy, sizeof(struct entropy), 2, RANDOM_UMA_ALLOC);
+#endif
+
#ifdef UMA_DEBUG_ALLOC_1
printf("Freeing item %p to %s(%p)\n", item, zone->uz_name, zone);
#endif
OpenPOWER on IntegriCloud