This is the much-discussed major upgrade to the random(4) device, known to you all as /dev/random.

This code has had an extensive rewrite and a good series of reviews, both by the author and other parties. This means a lot of code has been simplified. Pluggable structures for high-rate entropy generators are available, and it is most definitely not the case that /dev/random can be driven by only a hardware souce any more. This has been designed out of the device. Hardware sources are stirred into the CSPRNG (Yarrow, Fortuna) like any other entropy source. Pluggable modules may be written by third parties for additional sources.

The harvesting structures and consequently the locking have been simplified. Entropy harvesting is done in a more general way (the documentation for this will follow). There is some GREAT entropy to be had in the UMA allocator, but it is disabled for now as messing with that is likely to annoy many people.

The venerable (but effective) Yarrow algorithm, which is no longer supported by its authors now has an alternative, Fortuna. For now, Yarrow is retained as the default algorithm, but this may be changed using a kernel option. It is intended to make Fortuna the default algorithm for 11.0. Interested parties are encouraged to read ISBN 978-0-470-47424-2 "Cryptography Engineering" By Ferguson, Schneier and Kohno for Fortuna's gory details. Heck, read it anyway.

Many thanks to Arthur Mesh who did early grunt work, and who got caught in the crossfire rather more than he deserved to.

My thanks also to folks who helped me thresh this out on whiteboards and in the odd "Hallway track", or otherwise.

My Nomex pants are on. Let the feedback commence!

Reviewed by:	trasz,des(partial),imp(partial?),rwatson(partial?)
Approved by:	so(des)
This commit is contained in:
Mark Murray 2014-10-30 21:21:53 +00:00
parent 39d22d86ab
commit 10cb24248a
49 changed files with 2479 additions and 1543 deletions

View File

@ -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

View File

@ -57,7 +57,6 @@ FILES= DAEMON \
hostid_save \
hostname \
inetd \
initrandom \
ip6addrctl \
ipfilter \
ipfs \

View File

@ -28,7 +28,7 @@
#
# PROVIDE: disks
# REQUIRE: initrandom
# REQUIRE: random
# KEYWORD: nojail
. /etc/rc.subr

View File

@ -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"

View File

@ -4,7 +4,7 @@
#
# PROVIDE: postrandom
# REQUIRE: initrandom random FILESYSTEMS
# REQUIRE: random FILESYSTEMS
# BEFORE: LOGIN
# KEYWORD: nojail

View File

@ -4,7 +4,7 @@
#
# PROVIDE: random
# REQUIRE: initrandom FILESYSTEMS
# REQUIRE: FILESYSTEMS
# BEFORE: netif
# KEYWORD: nojail shutdown

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

24
sys/dev/random/build.sh Executable file
View File

@ -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

View File

@ -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);
#ifdef RANDOM_DEBUG
printf("random: %s\n", __func__);
#endif
randomdev_init_reader(dummy_random_read_phony);
}
static void
dummy_random_deinit(void)
/* 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;
mtx_destroy(&dummy_random_mtx);
}
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)
{
switch (type) {
case MOD_LOAD:
random_adaptor_register("dummy", &dummy_random);
EVENTHANDLER_INVOKE(random_adaptor_attach,
&dummy_random);
return (0);
if (!warned) {
log(LOG_WARNING, "random device not loaded/active; using insecure pseudo-random number generator\n");
warned = 1;
}
return (EINVAL);
/* srandom() is called in kern/init_main.c:proc0_post() */
/* 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 (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,
};

433
sys/dev/random/fortuna.c Normal file
View File

@ -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 */

View File

@ -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

View File

@ -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 */
}

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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) {
sbuf_new_for_sysctl(&sbuf, NULL, 64, req);
error = SYSCTL_OUT(req, ",", count++ ? 1 : 0);
if (error)
break;
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) {
read_rate = random_adaptor_read_rate();
LIST_FOREACH(lles, &les_sources, lles_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);
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.somecounter = get_cyclecount();
event.size = n;
event.bits = (n*8)/2;
event.source = les->rsource->source;
memcpy(event.entropy, buf, 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)
{
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");
}
void
live_entropy_sources_deinit(void)
{
sx_destroy(&les_lock);
}
SYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST,
live_entropy_sources_init, NULL);
SYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST,
live_entropy_sources_deinit, NULL);

View File

@ -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 */

View File

@ -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);

View File

@ -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,158 +29,348 @@
#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>
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;
struct random_adaptor *random_adaptor;
MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures");
int
random_adaptor_register(const char *name, struct random_adaptor *rsp)
{
struct random_adaptors *rpp;
KASSERT(name != NULL && rsp != NULL, ("invalid input to %s", __func__));
rpp = malloc(sizeof(struct random_adaptors), M_ENTROPY, M_WAITOK);
rpp->name = name;
rpp->rsp = rsp;
sx_xlock(&adaptors_lock);
LIST_INSERT_HEAD(&adaptors, rpp, entries);
sx_xunlock(&adaptors_lock);
return (0);
}
struct random_adaptor *
random_adaptor_get(const char *name)
{
struct random_adaptors *rpp;
struct random_adaptor *rsp;
rsp = NULL;
sx_slock(&adaptors_lock);
LIST_FOREACH(rpp, &adaptors, entries)
if (strcmp(rpp->name, name) == 0)
rsp = rpp->rsp;
sx_sunlock(&adaptors_lock);
return (rsp);
}
/*
* Walk a list of registered random(4) adaptors and pick the last non-selected
* one.
*
* If none are selected, use yarrow if available.
/* The random_adaptors_lock protects random_adaptors_list and friends and random_adaptor.
* We need a sleepable lock for uiomove/block/poll/sbuf/sysctl.
*/
void
random_adaptor_choose(struct random_adaptor **adaptor)
static struct sx random_adaptors_lock;
LIST_HEAD(adaptors_head, random_adaptors);
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 */
/* 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 */
static struct selinfo rsel;
/* 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)
{
char rngs[128], *token, *cp;
struct random_adaptors *rppi, *ramax;
unsigned primax;
struct random_adaptors *rra, *rrai;
struct random_adaptor *random_adaptor_previous;
int primax;
KASSERT(adaptor != NULL, ("pre-conditions failed"));
/* We are going to be messing with random_adaptor.
* Exclusive lock is mandatory.
*/
sx_assert(&random_adaptors_lock, SA_XLOCKED);
*adaptor = NULL;
random_adaptor_previous = random_adaptor;
random_adaptor = NULL;
if (TUNABLE_STR_FETCH("kern.random.active_adaptor", rngs, sizeof(rngs))) {
cp = rngs;
while ((token = strsep(&cp, ",")) != NULL)
if ((*adaptor = random_adaptor_get(token)) != NULL)
/* 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 if (bootverbose)
printf("%s random adaptor is not available,"
" skipping\n", token);
}
else
printf("random: requested adaptor <%s> not available\n",
token);
}
}
primax = 0U;
if (*adaptor == NULL) {
primax = 0;
if (random_adaptor == NULL) {
/*
* Fall back to the highest priority item on the available
* RNG list.
*/
sx_slock(&adaptors_lock);
ramax = NULL;
LIST_FOREACH(rppi, &adaptors, entries) {
if (rppi->rsp->priority >= primax) {
ramax = rppi;
primax = rppi->rsp->priority;
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 (ramax != NULL)
*adaptor = ramax->rsp;
if (random_adaptor != NULL)
printf("random: selecting highest priority adaptor <%s>\n",
random_adaptor->ra_ident);
}
sx_sunlock(&adaptors_lock);
KASSERT(random_adaptor != NULL, ("adaptor not found"));
if (bootverbose && *adaptor)
printf("Falling back to <%s> random adaptor\n",
(*adaptor)->ident);
/* 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)();
}
}
static void
random_adaptors_deinit(void *unused)
/* 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;
KASSERT(name != NULL && ra != NULL, ("invalid input to %s", __func__));
rra = malloc(sizeof(*rra), M_ENTROPY, M_WAITOK);
rra->rra_name = name;
rra->rra_ra = ra;
sx_xlock(&random_adaptors_lock);
LIST_INSERT_HEAD(&random_adaptors_list, rra, rra_entries);
random_adaptor_choose();
sx_xunlock(&random_adaptors_lock);
KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
}
void
random_adaptor_deregister(const char *name)
{
struct random_adaptors *rra;
KASSERT(name != NULL, ("invalid input to %s", __func__));
KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
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);
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);
}
mtx_lock(&random_read_rate_mtx);
/* 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);
}
/* Let the entropy source do any post-read cleanup. */
(random_adaptor->ra_read)(NULL, 1);
free(random_buf, M_ENTROPY);
}
sx_sunlock(&random_adaptors_lock);
return (error);
}
int
random_adaptor_read_rate(void)
{
int ret;
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);
}
/* ARGSUSED */
int
random_adaptor_write(struct cdev *dev __unused, struct uio *uio, int flags __unused)
{
int c, error = 0;
void *random_buf;
#ifdef RANDOM_DEBUG
printf("random: %s %zd\n", __func__, uio->uio_resid);
#endif
KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
sx_slock(&random_adaptors_lock);
random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
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);
}
free(random_buf, M_ENTROPY);
sx_sunlock(&random_adaptors_lock);
return (error);
}
/* ARGSUSED */
int
random_adaptor_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
{
sx_destroy(&adaptors_lock);
sysctl_ctx_free(&random_clist);
#ifdef RANDOM_DEBUG
printf("random: %s\n", __func__);
#endif
KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
sx_slock(&random_adaptors_lock);
if (events & (POLLIN | POLLRDNORM)) {
if (random_adaptor->ra_seeded())
events &= (POLLIN | POLLRDNORM);
else
selrecord(td, &rsel);
}
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 *rpp;
struct random_adaptors *rra;
struct sbuf sbuf;
int error, count;
count = error = 0;
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);
sx_slock(&adaptors_lock);
if (LIST_EMPTY(&adaptors))
error = SYSCTL_OUT(req, "", 0);
else {
LIST_FOREACH(rpp, &adaptors, entries) {
error = SYSCTL_OUT(req, ",", count++ ? 1 : 0);
if (error)
break;
error = SYSCTL_OUT(req, rpp->name, strlen(rpp->name));
if (error)
break;
}
}
sx_sunlock(&adaptors_lock);
error = sbuf_finish(&sbuf);
sbuf_delete(&sbuf);
sx_sunlock(&random_adaptors_lock);
return (error);
}
@ -188,36 +378,34 @@ random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS)
static int
random_sysctl_active_adaptor_handler(SYSCTL_HANDLER_ARGS)
{
struct random_adaptor *rsp;
struct random_adaptors *rpp;
const char *name;
struct random_adaptors *rra;
struct sbuf sbuf;
int error;
name = NULL;
rsp = random_adaptor;
KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
if (rsp != NULL) {
sx_slock(&adaptors_lock);
LIST_FOREACH(rpp, &adaptors, entries)
if (rpp->rsp == rsp)
name = rpp->name;
sx_sunlock(&adaptors_lock);
}
if (rsp == NULL || name == NULL)
error = SYSCTL_OUT(req, "", 0);
else
error = SYSCTL_OUT(req, name, strlen(name));
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);
}
static void
random_adaptors_init(void *unused)
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");
SYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, random_adaptors_init,
NULL);
SYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST,
random_adaptors_deinit, NULL);
static void
random_adaptors_reseed(void *unused)
void
random_adaptors_deinit(void)
{
(void)unused;
if (random_adaptor != NULL)
(*random_adaptor->reseed)();
#ifdef RANDOM_DEBUG
printf("random: %s\n", __func__);
#endif
live_entropy_sources_deinit();
/* 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_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);
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 */

View File

@ -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);
struct random_adaptors {
LIST_ENTRY(random_adaptors) entries; /* list of providers */
const char *name; /* name of random adaptor */
struct random_adaptor *rsp;
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_adaptor *random_adaptor_get(const char *);
int random_adaptor_register(const char *, struct random_adaptor *);
void random_adaptor_choose(struct random_adaptor **);
struct random_adaptors {
LIST_ENTRY(random_adaptors) rra_entries; /* list of providers */
const char *rra_name; /* name of random adaptor */
struct random_adaptor *rra_ra;
};
extern struct random_adaptor *random_adaptor;
/* Dummy "always-block" pseudo-device */
extern struct random_adaptor randomdev_dummy;
/*
* 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_adaptors_init(void);
void random_adaptors_deinit(void);
typedef void (*random_adaptor_attach_hook)(void *, struct random_adaptor *);
EVENTHANDLER_DECLARE(random_adaptor_attach, random_adaptor_attach_hook);
void random_adaptor_register(const char *, struct random_adaptor *);
void random_adaptor_deregister(const char *);
/* kern.random sysctls */
#ifdef SYSCTL_DECL /* from sysctl.h */
SYSCTL_DECL(_kern_random);
#endif /* SYSCTL_DECL */
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 *);
int random_adaptor_read_rate(void);
void random_adaptor_unblock(void);
#endif /* SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED */

View File

@ -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;
/* Empty entropy buffers */
static struct entropyfifo emptyfifo;
/* Round-robin destination cache. */
u_int harvest_destination[ENTROPYSOURCE];
/* Harvested entropy */
static struct entropyfifo harvestfifo;
/* Function called to process one harvested stochastic event */
void (*harvest_process_event)(struct harvest_event *);
/* Allow the sysadmin to select the broad category of
* entropy types to harvest.
*/
static u_int harvest_source_mask = ((1U << RANDOM_ENVIRONMENTAL_END) - 1);
/* 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
u_int maxloop, ring_out;
/* Get stuff that may have been preloaded by loader(8) */
keyfile = preload_search_by_type("/boot/entropy");
if (keyfile != NULL) {
data = preload_fetch_addr(keyfile);
size = preload_fetch_size(keyfile);
if (data != NULL && size != 0) {
for (i = 0; i < size; i += 16)
random_harvestq_internal(get_cyclecount(), data + i, 16, 16, RANDOM_CACHED);
printf("random: read %zu bytes from preloaded cache\n", size);
bzero(data, size);
}
else
printf("random: no preloaded entropy cache available\n");
}
#ifdef RANDOM_RWFILE
/* Read and attempt to overwrite the entropy cache files.
* If the file exists, can be read and then overwritten,
* then use it. Ignore it otherwise, but print out what is
* going on.
/*
* 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;) {
/* The ring may be filled quickly so don't loop forever. */
if (--maxloop)
break;
/*
* Grab all the entropy events.
* Drain entropy source records into a thread-local
* queue for processing while not holding the mutex.
*/
STAILQ_CONCAT(&local_queue, &harvestfifo.head);
local_count += harvestfifo.count;
harvestfifo.count = 0;
/*
* Deal with events, if any.
* 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 */
/* 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);
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);
}
emptyfifo.count = RANDOM_FIFO_MAX;
/* Will contain the queued-up events. */
STAILQ_INIT(&harvestfifo.head);
harvestfifo.count = 0;
return (error);
}
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);
}
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);
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;
/*
* 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;
/* 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);
/* 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++;
}
entropyfifo.ring_in = ring_in;
}
mtx_unlock_spin(&harvest_mtx);
}

View File

@ -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);
extern int random_kthread_control;
extern struct mtx harvest_mtx;
/* 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 *);
/* Round-robin destination cache. */
extern u_int harvest_destination[ENTROPYSOURCE];
#endif /* SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED */

View File

@ -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,96 +57,43 @@ __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;
/* ARGSUSED */
static int
random_read(struct cdev *dev __unused, struct uio *uio, int flag)
{
int c, error = 0;
void *random_buf;
/* Set up the sysctl root node for the entropy device */
SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Random Number Generator");
/* 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);
while (uio->uio_resid > 0 && !error) {
c = MIN(uio->uio_resid, PAGE_SIZE);
c = (*random_adaptor->read)(random_buf, c);
error = uiomove(random_buf, c, uio);
}
/* Finished reading; let the source know so it can do some
* optional housekeeping */
(*random_adaptor->read)(NULL, 0);
free(random_buf, M_ENTROPY);
}
return (error);
}
MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures");
/* ARGSUSED */
static int
random_write(struct cdev *dev __unused, struct uio *uio, int flag __unused)
{
/* 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);
}
/* ARGSUSED */
static int
random_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
int flags __unused, struct thread *td __unused)
{
int error = 0;
@ -137,85 +103,48 @@ random_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
case FIOASYNC:
case FIONBIO:
break;
default:
error = ENOTTY;
}
return (error);
}
/* ARGSUSED */
static int
random_poll(struct cdev *dev __unused, int events, struct thread *td)
/* 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)
{
int revents = 0;
if (events & (POLLIN | POLLRDNORM)) {
if (random_adaptor->seeded)
revents = events & (POLLIN | POLLRDNORM);
else
revents = (*random_adaptor->poll)(events, td);
}
return (revents);
}
static void
random_initialize(void *p, struct random_adaptor *s)
{
static int random_inited = 0;
if (random_inited) {
printf("random: <%s> already initialized\n",
random_adaptor->ident);
return;
}
random_adaptor = s;
(s->init)();
printf("random: <%s> initialized\n", s->ident);
/* Use an appropriately evil mode for those who are concerned
* with daemons */
random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw,
RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0666, "random");
make_dev_alias(random_dev, "urandom"); /* compatibility */
/* mark random(4) as initialized, to avoid being called again */
random_inited = 1;
wakeup(control);
kproc_exit(0);
/* NOTREACHED */
}
/* ARGSUSED */
static int
random_modevent(module_t mod __unused, int type, void *data __unused)
randomdev_modevent(module_t mod __unused, int type, void *data __unused)
{
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);
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:
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);
random_adaptors_deinit();
destroy_dev(random_dev);
break;
case MOD_SHUTDOWN:
@ -226,8 +155,98 @@ random_modevent(module_t mod __unused, int type, void *data __unused)
break;
}
return (error);
}
DEV_MODULE(random, random_modevent, NULL);
MODULE_VERSION(random, 1);
#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)
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_harvest_phony(const void *entropy __unused, u_int count __unused,
u_int bits __unused, enum random_entropy_source origin __unused)
{
}
/* 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;
/* Initialise the harvester when/if it is loaded */
void
randomdev_init_harvester(void (*reaper)(const void *, u_int, u_int, enum random_entropy_source))
{
reap_func = reaper;
}
/* Deinitialise the harvester when/if it is unloaded */
void
randomdev_deinit_harvester(void)
{
reap_func = random_harvest_phony;
}
/* 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)
{
(*reap_func)(entropy, count, bits, origin);
}
/* ================================
* Internal reading stubs and fakes
* ================================
*/
/* Hold the address of the routine which is actually called */
static u_int (*read_func)(uint8_t *, u_int) = dummy_random_read_phony;
/* Initialise the reader when/if it is loaded */
void
randomdev_init_reader(u_int (*reader)(uint8_t *, u_int))
{
read_func = reader;
}
/* Deinitialise the reader when/if it is unloaded */
void
randomdev_deinit_reader(void)
{
read_func = dummy_random_read_phony;
}
/* 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));
}

View File

@ -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;
};
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);
struct random_hardware_source {
const char *ident;
enum esource source;
random_read_func_t *read;
};
/* 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

View File

@ -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)
{
int revents = 0;
mtx_lock(&random_reseed_mtx);
if (random_context.seeded)
revents = events & (POLLIN | POLLRDNORM);
else
selrecord(td, &random_context.rsel);
mtx_unlock(&random_reseed_mtx);
return (revents);
}
static int
randomdev_block(int flag)
randomdev_soft_modevent(module_t mod __unused, int type, void *unused __unused)
{
int error = 0;
mtx_lock(&random_reseed_mtx);
switch (type) {
case MOD_LOAD:
printf("random: SOFT: %s init()\n", RANDOM_CSPRNG_NAME);
random_adaptor_register(RANDOM_CSPRNG_NAME, &random_soft_processor);
break;
case MOD_UNLOAD:
random_adaptor_deregister(RANDOM_CSPRNG_NAME);
break;
case MOD_SHUTDOWN:
break;
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);

View File

@ -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

View File

@ -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

75
sys/dev/random/uint128.h Normal file
View File

@ -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 */

257
sys/dev/random/unit_test.c Normal file
View File

@ -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);
}

View File

@ -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 */

View File

@ -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);
/* if enough slow sources are over threshhold, reseed */
if (overthreshhold[SLOW] >= random_state.slowoverthresh)
reseed(SLOW);
/* Invert the fast/slow pool selector bit */
random_state.which = !random_state.which;
}
void
random_yarrow_init_alg(struct sysctl_ctx_list *clist)
{
int i;
int i, j;
#ifdef _KERNEL
struct sysctl_oid *random_yarrow_o;
#endif /* _KERNEL */
memset(yarrow_state.start_cache.junk, 0, KEYSIZE);
randomdev_hash_init(&yarrow_state.start_cache.hash);
/* 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 */
/* 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");
KASSERT(yarrow_state.pool[FAST].thresh > 0, ("random: Yarrow fast threshold = 0"));
KASSERT(yarrow_state.pool[SLOW].thresh > 0, ("random: Yarrow slow threshold = 0"));
#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
/* The reseed task must not be jumped on */
mtx_lock(&random_reseed_mtx);
/* 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 */
/* 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
/* Unblock the device if it was blocked due to being unseeded */
randomdev_unblock();
/* Release the reseed mutex */
mtx_unlock(&random_reseed_mtx);
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;
}
}
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;
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;
}
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 */

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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();

View File

@ -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);

View File

@ -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);

View File

@ -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 */

View File

@ -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 @@ uma_zalloc_arg(uma_zone_t zone, void *udata, int flags)
#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 @@ uma_zalloc_arg(uma_zone_t zone, void *udata, int flags)
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