SNAPSHOT.
Simplify the malloc pools; We only need one for this device. Simplify the harvest queue. Marginally improve the entropy pool hashing, making it a bit faster in the process. Connect up the hardware "live" source harvesting. This is simplistic for now, and will need to be made rate-adaptive. All of the above passes a compile test but needs to be debugged.
This commit is contained in:
parent
21998ad688
commit
efb299b5bd
@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/selinfo.h>
|
||||
|
@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.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>
|
||||
@ -40,9 +41,11 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/specialreg.h>
|
||||
|
||||
#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/randomdev.h>
|
||||
|
||||
#define RETRY_COUNT 10
|
||||
|
||||
|
@ -40,9 +40,12 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/systm.h>
|
||||
#include <sys/unistd.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 "live_entropy_sources.h"
|
||||
|
||||
@ -52,9 +55,6 @@ static struct sx les_lock; /* need a sleepable lock */
|
||||
|
||||
#define LES_THRESHOLD 10
|
||||
|
||||
MALLOC_DEFINE(M_LIVE_ENTROPY_SRCS, "live_entropy_sources",
|
||||
"Live Entropy Sources");
|
||||
|
||||
void
|
||||
live_entropy_source_register(struct random_hardware_source *rsource)
|
||||
{
|
||||
@ -62,8 +62,7 @@ live_entropy_source_register(struct random_hardware_source *rsource)
|
||||
|
||||
KASSERT(rsource != NULL, ("invalid input to %s", __func__));
|
||||
|
||||
les = malloc(sizeof(struct live_entropy_sources), M_LIVE_ENTROPY_SRCS,
|
||||
M_WAITOK);
|
||||
les = malloc(sizeof(struct live_entropy_sources), M_ENTROPY, M_WAITOK);
|
||||
les->rsource = rsource;
|
||||
|
||||
sx_xlock(&les_lock);
|
||||
@ -82,7 +81,7 @@ live_entropy_source_deregister(struct random_hardware_source *rsource)
|
||||
LIST_FOREACH(les, &sources, entries) {
|
||||
if (les->rsource == rsource) {
|
||||
LIST_REMOVE(les, entries);
|
||||
free(les, M_LIVE_ENTROPY_SRCS);
|
||||
free(les, M_ENTROPY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -136,12 +135,16 @@ live_entropy_sources_init(void *unused)
|
||||
* number of rounds, which should be a multiple of the number
|
||||
* of entropy accumulation pools in use; 2 for Yarrow and 32
|
||||
* for Fortuna.
|
||||
*
|
||||
* BEWARE!!!
|
||||
* This function runs inside the RNG thread! Don't do anything silly!
|
||||
*/
|
||||
void
|
||||
live_entropy_sources_feed(int rounds)
|
||||
live_entropy_sources_feed(int rounds, event_proc_f entropy_processor)
|
||||
{
|
||||
static struct harvest event;
|
||||
static uint8_t buf[HARVESTSIZE];
|
||||
struct live_entropy_sources *les;
|
||||
uint8_t buf[HARVESTSIZE];
|
||||
int i, n;
|
||||
|
||||
sx_slock(&les_lock);
|
||||
@ -157,14 +160,19 @@ live_entropy_sources_feed(int rounds)
|
||||
* This should be quick, since it's a live entropy
|
||||
* source.
|
||||
*/
|
||||
n = les->rsource->read(buf, sizeof(buf));
|
||||
/* FIXME: Whine loudly if this didn't work. */
|
||||
n = les->rsource->read(buf, sizeof(buf));
|
||||
n = MIN(n, HARVESTSIZE);
|
||||
|
||||
event.somecounter = get_cyclecount();
|
||||
event.size = n;
|
||||
event.bits = (n*8)/2;
|
||||
event.source = les->rsource->source;
|
||||
memcpy(event.entropy, buf, n);
|
||||
|
||||
/* Do the actual entropy insertion */
|
||||
entropy_processor(&event);
|
||||
|
||||
/*
|
||||
* FIXME: Cannot harvest this stuff into the queue;
|
||||
* the poor thing will choke to death!
|
||||
*/
|
||||
random_harvest(buf, n, 0, les->rsource->source);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ struct live_entropy_sources {
|
||||
|
||||
void live_entropy_source_register(struct random_hardware_source *);
|
||||
void live_entropy_source_deregister(struct random_hardware_source *);
|
||||
void live_entropy_sources_feed(int);
|
||||
void live_entropy_sources_feed(int, event_proc_f);
|
||||
|
||||
#define LIVE_ENTROPY_SRC_MODULE(name, modevent, ver) \
|
||||
static moduledata_t name##_mod = { \
|
||||
|
@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.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>
|
||||
@ -40,9 +41,11 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/specialreg.h>
|
||||
|
||||
#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/randomdev.h>
|
||||
|
||||
static void random_nehemiah_init(void);
|
||||
static void random_nehemiah_deinit(void);
|
||||
|
@ -55,8 +55,6 @@ static struct sysctl_ctx_list random_clist;
|
||||
|
||||
struct random_adaptor *random_adaptor;
|
||||
|
||||
MALLOC_DEFINE(M_RANDOM_ADAPTORS, "random_adaptors", "Random adaptors buffers");
|
||||
|
||||
int
|
||||
random_adaptor_register(const char *name, struct random_adaptor *rsp)
|
||||
{
|
||||
@ -64,8 +62,7 @@ random_adaptor_register(const char *name, struct random_adaptor *rsp)
|
||||
|
||||
KASSERT(name != NULL && rsp != NULL, ("invalid input to %s", __func__));
|
||||
|
||||
rpp = malloc(sizeof(struct random_adaptors), M_RANDOM_ADAPTORS,
|
||||
M_WAITOK);
|
||||
rpp = malloc(sizeof(struct random_adaptors), M_ENTROPY, M_WAITOK);
|
||||
rpp->name = name;
|
||||
rpp->rsp = rsp;
|
||||
|
||||
|
@ -39,17 +39,17 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/selinfo.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/unistd.h>
|
||||
|
||||
#include <dev/random/randomdev.h>
|
||||
#include <dev/random/randomdev_soft.h>
|
||||
|
||||
#include "random_harvestq.h"
|
||||
#include <dev/random/random_harvestq.h>
|
||||
#include <dev/random/live_entropy_sources.h>
|
||||
|
||||
#define RANDOM_FIFO_MAX 1024 /* How many events to queue up */
|
||||
|
||||
MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers");
|
||||
|
||||
/*
|
||||
* The harvest mutex protects the consistency of the entropy fifos and
|
||||
* empty fifo.
|
||||
@ -66,7 +66,7 @@ struct entropyfifo {
|
||||
static struct entropyfifo emptyfifo;
|
||||
|
||||
/* Harvested entropy */
|
||||
static struct entropyfifo harvestfifo[ENTROPYSOURCE];
|
||||
static struct entropyfifo harvestfifo;
|
||||
|
||||
/* <0 to end the kthread, 0 to let it run, 1 to flush the harvest queues */
|
||||
int random_kthread_control = 0;
|
||||
@ -79,8 +79,7 @@ random_kthread(void *arg)
|
||||
STAILQ_HEAD(, harvest) local_queue;
|
||||
struct harvest *event = NULL;
|
||||
int local_count;
|
||||
enum esource source;
|
||||
event_proc_f func = arg;
|
||||
event_proc_f entropy_processor = arg;
|
||||
|
||||
STAILQ_INIT(&local_queue);
|
||||
local_count = 0;
|
||||
@ -89,16 +88,14 @@ random_kthread(void *arg)
|
||||
mtx_lock_spin(&harvest_mtx);
|
||||
for (; random_kthread_control >= 0;) {
|
||||
|
||||
/* Cycle through all the entropy sources */
|
||||
for (source = RANDOM_START; source < ENTROPYSOURCE; source++) {
|
||||
/*
|
||||
* Drain entropy source records into a thread-local
|
||||
* queue for processing while not holding the mutex.
|
||||
*/
|
||||
STAILQ_CONCAT(&local_queue, &harvestfifo[source].head);
|
||||
local_count += harvestfifo[source].count;
|
||||
harvestfifo[source].count = 0;
|
||||
}
|
||||
/*
|
||||
* Grab all the entropy events.
|
||||
* Drain entropy source records into a thread-local
|
||||
* queue for processing while not holding the mutex.
|
||||
*/
|
||||
STAILQ_CONCAT(&local_queue, &harvestfifo.head);
|
||||
local_count += harvestfifo.count;
|
||||
harvestfifo.count = 0;
|
||||
|
||||
/*
|
||||
* Deal with events, if any.
|
||||
@ -107,7 +104,7 @@ random_kthread(void *arg)
|
||||
if (!STAILQ_EMPTY(&local_queue)) {
|
||||
mtx_unlock_spin(&harvest_mtx);
|
||||
STAILQ_FOREACH(event, &local_queue, next)
|
||||
func(event);
|
||||
entropy_processor(event);
|
||||
mtx_lock_spin(&harvest_mtx);
|
||||
STAILQ_CONCAT(&emptyfifo.head, &local_queue);
|
||||
emptyfifo.count += local_count;
|
||||
@ -118,16 +115,10 @@ random_kthread(void *arg)
|
||||
local_count));
|
||||
|
||||
/*
|
||||
* Do Hardware/fast RNG source processing here.
|
||||
* Do only one round of the hardware sources for now.
|
||||
* Later we'll need to make it rate-adaptive.
|
||||
*/
|
||||
#if 0
|
||||
while (hardware_source) {
|
||||
event = hardware_source->read();
|
||||
func(event);
|
||||
hardware_source++;
|
||||
/* Throttle somehow? */
|
||||
}
|
||||
#endif
|
||||
live_entropy_sources_feed(1, entropy_processor);
|
||||
|
||||
/*
|
||||
* If a queue flush was commanded, it has now happened,
|
||||
@ -153,23 +144,23 @@ random_harvestq_init(event_proc_f cb)
|
||||
{
|
||||
int error, i;
|
||||
struct harvest *np;
|
||||
enum esource e;
|
||||
|
||||
/* Initialise the harvest fifos */
|
||||
|
||||
/* Contains the currently unused event structs. */
|
||||
STAILQ_INIT(&emptyfifo.head);
|
||||
emptyfifo.count = 0;
|
||||
for (i = 0; i < RANDOM_FIFO_MAX; i++) {
|
||||
np = malloc(sizeof(struct harvest), M_ENTROPY, M_WAITOK);
|
||||
STAILQ_INSERT_TAIL(&emptyfifo.head, np, next);
|
||||
}
|
||||
for (e = RANDOM_START; e < ENTROPYSOURCE; e++) {
|
||||
STAILQ_INIT(&harvestfifo[e].head);
|
||||
harvestfifo[e].count = 0;
|
||||
}
|
||||
emptyfifo.count = RANDOM_FIFO_MAX;
|
||||
|
||||
/* Will contain the queued-up events. */
|
||||
STAILQ_INIT(&harvestfifo.head);
|
||||
harvestfifo.count = 0;
|
||||
|
||||
mtx_init(&harvest_mtx, "entropy harvest mutex", NULL, MTX_SPIN);
|
||||
|
||||
|
||||
/* Start the hash/reseed thread */
|
||||
error = kproc_create(random_kthread, cb,
|
||||
&random_kthread_proc, RFHIGHPID, 0, "rand_harvestq"); /* RANDOM_CSPRNG_NAME */
|
||||
@ -182,7 +173,6 @@ void
|
||||
random_harvestq_deinit(void)
|
||||
{
|
||||
struct harvest *np;
|
||||
enum esource e;
|
||||
|
||||
/* Destroy the harvest fifos */
|
||||
while (!STAILQ_EMPTY(&emptyfifo.head)) {
|
||||
@ -190,20 +180,26 @@ random_harvestq_deinit(void)
|
||||
STAILQ_REMOVE_HEAD(&emptyfifo.head, next);
|
||||
free(np, M_ENTROPY);
|
||||
}
|
||||
for (e = RANDOM_START; e < ENTROPYSOURCE; e++) {
|
||||
while (!STAILQ_EMPTY(&harvestfifo[e].head)) {
|
||||
np = STAILQ_FIRST(&harvestfifo[e].head);
|
||||
STAILQ_REMOVE_HEAD(&harvestfifo[e].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;
|
||||
|
||||
mtx_destroy(&harvest_mtx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Entropy harvesting routine. This is supposed to be fast; do
|
||||
* not do anything slow in here!
|
||||
* Entropy harvesting routine.
|
||||
* This is supposed to be fast; do not do anything slow in here!
|
||||
*
|
||||
* It is also illegal (and morally reprehensible) to insert any
|
||||
* high-rate data here. "High-rate" is define as a data source
|
||||
* that will usually cause lots of failures of the "Lockless read"
|
||||
* check a few lines below. This includes the "always-on" sources
|
||||
* like the Intel "rdrand" or the VIA Nehamiah "xstore" sources.
|
||||
*/
|
||||
void
|
||||
random_harvestq_internal(u_int64_t somecounter, const void *entropy,
|
||||
@ -215,21 +211,21 @@ random_harvestq_internal(u_int64_t somecounter, const void *entropy,
|
||||
("random_harvest_internal: origin %d invalid\n", origin));
|
||||
|
||||
/* Lockless read to avoid lock operations if fifo is full. */
|
||||
if (harvestfifo[origin].count >= RANDOM_FIFO_MAX)
|
||||
if (harvestfifo.count >= RANDOM_FIFO_MAX)
|
||||
return;
|
||||
|
||||
mtx_lock_spin(&harvest_mtx);
|
||||
|
||||
/*
|
||||
* Don't make the harvest queues too big - help to prevent low-grade
|
||||
* entropy swamping
|
||||
* On't overfill the harvest queue; this could steal all
|
||||
* our memory.
|
||||
*/
|
||||
if (harvestfifo[origin].count < RANDOM_FIFO_MAX) {
|
||||
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);
|
||||
harvestfifo[origin].count++;
|
||||
emptyfifo.count--;
|
||||
event->somecounter = somecounter;
|
||||
event->size = count;
|
||||
event->bits = bits;
|
||||
@ -239,21 +235,11 @@ random_harvestq_internal(u_int64_t somecounter, const void *entropy,
|
||||
count = MIN(count, HARVESTSIZE);
|
||||
memcpy(event->entropy, entropy, count);
|
||||
|
||||
#if 0
|
||||
{
|
||||
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
|
||||
|
||||
STAILQ_INSERT_TAIL(&harvestfifo[origin].head,
|
||||
STAILQ_INSERT_TAIL(&harvestfifo.head,
|
||||
event, next);
|
||||
harvestfifo.count++;
|
||||
}
|
||||
}
|
||||
|
||||
mtx_unlock_spin(&harvest_mtx);
|
||||
}
|
||||
|
@ -52,9 +52,11 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/bus.h>
|
||||
#include <machine/cpu.h>
|
||||
|
||||
#include <dev/random/random_adaptors.h>
|
||||
#include <dev/random/live_entropy_sources.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
|
||||
|
||||
@ -72,6 +74,8 @@ static struct cdevsw random_cdevsw = {
|
||||
.d_name = "random",
|
||||
};
|
||||
|
||||
MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers");
|
||||
|
||||
/* For use with make_dev(9)/destroy_dev(9). */
|
||||
static struct cdev *random_dev;
|
||||
|
||||
@ -82,10 +86,6 @@ random_read(struct cdev *dev __unused, struct uio *uio, int flag)
|
||||
int c, error = 0;
|
||||
void *random_buf;
|
||||
|
||||
/* XXX: Harvest some entropy from live entropy sources, if available */
|
||||
live_entropy_sources_feed(65); /* 65 is meaningless --
|
||||
need to decide appropriate value */
|
||||
|
||||
/* Blocking logic */
|
||||
if (!random_adaptor->seeded)
|
||||
error = (*random_adaptor->block)(flag);
|
||||
@ -93,7 +93,7 @@ random_read(struct cdev *dev __unused, struct uio *uio, int flag)
|
||||
/* The actual read */
|
||||
if (!error) {
|
||||
|
||||
random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
|
||||
random_buf = (void *)malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
|
||||
|
||||
while (uio->uio_resid > 0 && !error) {
|
||||
c = MIN(uio->uio_resid, PAGE_SIZE);
|
||||
@ -104,7 +104,7 @@ random_read(struct cdev *dev __unused, struct uio *uio, int flag)
|
||||
* optional housekeeping */
|
||||
(*random_adaptor->read)(NULL, 0);
|
||||
|
||||
free(random_buf, M_TEMP);
|
||||
free(random_buf, M_ENTROPY);
|
||||
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,8 @@
|
||||
* and non algorithm-specific for the entropy processor
|
||||
*/
|
||||
|
||||
MALLOC_DECLARE(M_ENTROPY);
|
||||
|
||||
typedef void random_init_func_t(void);
|
||||
typedef void random_deinit_func_t(void);
|
||||
typedef int random_block_func_t(int);
|
||||
|
@ -53,9 +53,10 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/bus.h>
|
||||
#include <machine/cpu.h>
|
||||
|
||||
#include <dev/random/random_adaptors.h>
|
||||
#include <dev/random/randomdev.h>
|
||||
#include <dev/random/randomdev_soft.h>
|
||||
#include <dev/random/random_harvestq.h>
|
||||
#include <dev/random/random_adaptors.h>
|
||||
#if defined(YARROW_RNG)
|
||||
#include <dev/random/yarrow.h>
|
||||
#endif
|
||||
@ -63,7 +64,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <dev/random/fortuna.h>
|
||||
#endif
|
||||
|
||||
#include "random_harvestq.h"
|
||||
|
||||
static int randomdev_poll(int event, struct thread *td);
|
||||
static int randomdev_block(int flag);
|
||||
|
@ -41,8 +41,6 @@
|
||||
|
||||
#define HARVESTSIZE 16 /* max size of each harvested entropy unit */
|
||||
|
||||
MALLOC_DECLARE(M_ENTROPY);
|
||||
|
||||
/* These are used to queue harvested packets of entropy. The entropy
|
||||
* buffer size is pretty arbitrary.
|
||||
*/
|
||||
|
@ -97,6 +97,7 @@ clear_counter(void)
|
||||
|
||||
/* 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)
|
||||
{
|
||||
@ -113,13 +114,25 @@ random_process_event(struct harvest *event)
|
||||
struct source *source;
|
||||
enum esource src;
|
||||
|
||||
/* Unpack the event into the appropriate source accumulator */
|
||||
#if 1
|
||||
/* 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->entropy,
|
||||
sizeof(event->entropy));
|
||||
randomdev_hash_iterate(&random_state.pool[pl].hash, &event->somecounter,
|
||||
sizeof(event->somecounter));
|
||||
randomdev_hash_iterate(&random_state.pool[pl].hash, event,
|
||||
sizeof(*event));
|
||||
source->bits += event->bits;
|
||||
|
||||
/* Count the over-threshold sources in each pool */
|
||||
|
Loading…
x
Reference in New Issue
Block a user