1255071Smarkm/*- 2256381Smarkm * Copyright (c) 2000-2013 Mark R V Murray 3255071Smarkm * Copyright (c) 2013 Arthur Mesh 4255071Smarkm * Copyright (c) 2004 Robert N. M. Watson 5255071Smarkm * All rights reserved. 6255071Smarkm * 7255071Smarkm * Redistribution and use in source and binary forms, with or without 8255071Smarkm * modification, are permitted provided that the following conditions 9255071Smarkm * are met: 10255071Smarkm * 1. Redistributions of source code must retain the above copyright 11255071Smarkm * notice, this list of conditions and the following disclaimer 12255071Smarkm * in this position and unchanged. 13255071Smarkm * 2. Redistributions in binary form must reproduce the above copyright 14255071Smarkm * notice, this list of conditions and the following disclaimer in the 15255071Smarkm * documentation and/or other materials provided with the distribution. 16255071Smarkm * 17255071Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18255071Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19255071Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20255071Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21255071Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22255071Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23255071Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24255071Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25255071Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26255071Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27255071Smarkm * 28255071Smarkm */ 29255071Smarkm 30255071Smarkm#include <sys/cdefs.h> 31255071Smarkm__FBSDID("$FreeBSD$"); 32255071Smarkm 33256381Smarkm#include "opt_random.h" 34256381Smarkm 35255071Smarkm#include <sys/param.h> 36255071Smarkm#include <sys/systm.h> 37256381Smarkm#include <sys/eventhandler.h> 38255071Smarkm#include <sys/kernel.h> 39255071Smarkm#include <sys/kthread.h> 40256381Smarkm#include <sys/linker.h> 41255071Smarkm#include <sys/lock.h> 42255071Smarkm#include <sys/malloc.h> 43255071Smarkm#include <sys/mutex.h> 44255071Smarkm#include <sys/random.h> 45256381Smarkm#include <sys/selinfo.h> 46255071Smarkm#include <sys/sysctl.h> 47255071Smarkm#include <sys/unistd.h> 48255071Smarkm 49256381Smarkm#include <machine/cpu.h> 50256381Smarkm#include <machine/vmparam.h> 51256381Smarkm 52256381Smarkm#include <dev/random/randomdev.h> 53255071Smarkm#include <dev/random/randomdev_soft.h> 54256381Smarkm#include <dev/random/random_adaptors.h> 55256381Smarkm#include <dev/random/random_harvestq.h> 56256381Smarkm#include <dev/random/live_entropy_sources.h> 57256381Smarkm#include <dev/random/rwfile.h> 58255071Smarkm 59256381Smarkm#define RANDOM_FIFO_MAX 1024 /* How many events to queue up */ 60255071Smarkm 61255071Smarkm/* 62255071Smarkm * The harvest mutex protects the consistency of the entropy fifos and 63256381Smarkm * empty fifo and other associated structures. 64255071Smarkm */ 65255071Smarkmstruct mtx harvest_mtx; 66255071Smarkm 67255071Smarkm/* Lockable FIFO queue holding entropy buffers */ 68255071Smarkmstruct entropyfifo { 69255071Smarkm int count; 70255071Smarkm STAILQ_HEAD(harvestlist, harvest) head; 71255071Smarkm}; 72255071Smarkm 73255071Smarkm/* Empty entropy buffers */ 74255071Smarkmstatic struct entropyfifo emptyfifo; 75255071Smarkm 76255071Smarkm/* Harvested entropy */ 77256381Smarkmstatic struct entropyfifo harvestfifo; 78255071Smarkm 79255071Smarkm/* <0 to end the kthread, 0 to let it run, 1 to flush the harvest queues */ 80255071Smarkmint random_kthread_control = 0; 81255071Smarkm 82255071Smarkmstatic struct proc *random_kthread_proc; 83255071Smarkm 84295480Sjhbstatic event_proc_f random_cb; 85295480Sjhb 86256381Smarkm#ifdef RANDOM_RWFILE 87256381Smarkmstatic const char *entropy_files[] = { 88256381Smarkm "/entropy", 89256381Smarkm NULL 90256381Smarkm}; 91256381Smarkm#endif 92256381Smarkm 93256381Smarkm/* Deal with entropy cached externally if this is present. 94256381Smarkm * Lots of policy may eventually arrive in this function. 95256381Smarkm * Called after / is mounted. 96256381Smarkm */ 97255071Smarkmstatic void 98256381Smarkmrandom_harvestq_cache(void *arg __unused) 99256381Smarkm{ 100256381Smarkm uint8_t *keyfile, *data; 101256381Smarkm size_t size, i; 102256381Smarkm#ifdef RANDOM_RWFILE 103256381Smarkm const char **entropy_file; 104256381Smarkm uint8_t *zbuf; 105256381Smarkm int error; 106256381Smarkm#endif 107256381Smarkm 108256381Smarkm /* Get stuff that may have been preloaded by loader(8) */ 109256381Smarkm keyfile = preload_search_by_type("/boot/entropy"); 110256381Smarkm if (keyfile != NULL) { 111256381Smarkm data = preload_fetch_addr(keyfile); 112256381Smarkm size = preload_fetch_size(keyfile); 113256381Smarkm if (data != NULL && size != 0) { 114256381Smarkm for (i = 0; i < size; i += 16) 115256381Smarkm random_harvestq_internal(get_cyclecount(), data + i, 16, 16, RANDOM_CACHED); 116256381Smarkm printf("random: read %zu bytes from preloaded cache\n", size); 117256381Smarkm bzero(data, size); 118256381Smarkm } 119256381Smarkm else 120256381Smarkm printf("random: no preloaded entropy cache available\n"); 121256381Smarkm } 122256381Smarkm 123256381Smarkm#ifdef RANDOM_RWFILE 124256381Smarkm /* Read and attempt to overwrite the entropy cache files. 125256381Smarkm * If the file exists, can be read and then overwritten, 126256381Smarkm * then use it. Ignore it otherwise, but print out what is 127256381Smarkm * going on. 128256381Smarkm */ 129256381Smarkm data = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); 130256381Smarkm zbuf = __DECONST(void *, zero_region); 131256381Smarkm for (entropy_file = entropy_files; *entropy_file; entropy_file++) { 132256381Smarkm error = randomdev_read_file(*entropy_file, data, PAGE_SIZE); 133256381Smarkm if (error == 0) { 134256381Smarkm printf("random: entropy cache '%s' provides %ld bytes\n", *entropy_file, (long)PAGE_SIZE); 135256381Smarkm error = randomdev_write_file(*entropy_file, zbuf, PAGE_SIZE); 136256381Smarkm if (error == 0) { 137256381Smarkm printf("random: entropy cache '%s' contents used and successfully overwritten\n", *entropy_file); 138256381Smarkm for (i = 0; i < PAGE_SIZE; i += 16) 139256381Smarkm random_harvestq_internal(get_cyclecount(), data + i, 16, 16, RANDOM_CACHED); 140256381Smarkm } 141256381Smarkm else 142256381Smarkm printf("random: entropy cache '%s' not overwritten and therefore not used; error = %d\n", *entropy_file, error); 143256381Smarkm } 144256381Smarkm else 145256381Smarkm printf("random: entropy cache '%s' not present or unreadable; error = %d\n", *entropy_file, error); 146256381Smarkm } 147256381Smarkm bzero(data, PAGE_SIZE); 148256381Smarkm free(data, M_ENTROPY); 149256381Smarkm#endif 150256381Smarkm} 151256381SmarkmEVENTHANDLER_DEFINE(mountroot, random_harvestq_cache, NULL, 0); 152256381Smarkm 153256381Smarkmstatic void 154255071Smarkmrandom_kthread(void *arg) 155255071Smarkm{ 156255071Smarkm STAILQ_HEAD(, harvest) local_queue; 157255071Smarkm struct harvest *event = NULL; 158255071Smarkm int local_count; 159256381Smarkm event_proc_f entropy_processor = arg; 160255071Smarkm 161255071Smarkm STAILQ_INIT(&local_queue); 162255071Smarkm local_count = 0; 163255071Smarkm 164255071Smarkm /* Process until told to stop */ 165255071Smarkm mtx_lock_spin(&harvest_mtx); 166255071Smarkm for (; random_kthread_control >= 0;) { 167255071Smarkm 168256381Smarkm /* 169256381Smarkm * Grab all the entropy events. 170256381Smarkm * Drain entropy source records into a thread-local 171256381Smarkm * queue for processing while not holding the mutex. 172256381Smarkm */ 173256381Smarkm STAILQ_CONCAT(&local_queue, &harvestfifo.head); 174256381Smarkm local_count += harvestfifo.count; 175256381Smarkm harvestfifo.count = 0; 176255071Smarkm 177255071Smarkm /* 178256381Smarkm * Deal with events, if any. 179256381Smarkm * Then transfer the used events back into the empty fifo. 180255071Smarkm */ 181255071Smarkm if (!STAILQ_EMPTY(&local_queue)) { 182255071Smarkm mtx_unlock_spin(&harvest_mtx); 183255071Smarkm STAILQ_FOREACH(event, &local_queue, next) 184256381Smarkm entropy_processor(event); 185255071Smarkm mtx_lock_spin(&harvest_mtx); 186255071Smarkm STAILQ_CONCAT(&emptyfifo.head, &local_queue); 187255071Smarkm emptyfifo.count += local_count; 188255071Smarkm local_count = 0; 189255071Smarkm } 190255071Smarkm 191255071Smarkm KASSERT(local_count == 0, ("random_kthread: local_count %d", 192255071Smarkm local_count)); 193255071Smarkm 194255071Smarkm /* 195256381Smarkm * Do only one round of the hardware sources for now. 196256381Smarkm * Later we'll need to make it rate-adaptive. 197256381Smarkm */ 198256381Smarkm mtx_unlock_spin(&harvest_mtx); 199256381Smarkm live_entropy_sources_feed(1, entropy_processor); 200256381Smarkm mtx_lock_spin(&harvest_mtx); 201256381Smarkm 202256381Smarkm /* 203255071Smarkm * If a queue flush was commanded, it has now happened, 204255071Smarkm * and we can mark this by resetting the command. 205255071Smarkm */ 206256381Smarkm 207255071Smarkm if (random_kthread_control == 1) 208255071Smarkm random_kthread_control = 0; 209255071Smarkm 210255071Smarkm /* Work done, so don't belabour the issue */ 211255071Smarkm msleep_spin_sbt(&random_kthread_control, &harvest_mtx, 212256381Smarkm "-", SBT_1S/10, 0, C_PREL(1)); 213255071Smarkm 214255071Smarkm } 215255071Smarkm mtx_unlock_spin(&harvest_mtx); 216255071Smarkm 217255071Smarkm random_set_wakeup_exit(&random_kthread_control); 218255071Smarkm /* NOTREACHED */ 219255071Smarkm} 220255071Smarkm 221255071Smarkmvoid 222255071Smarkmrandom_harvestq_init(event_proc_f cb) 223255071Smarkm{ 224295480Sjhb int i; 225255071Smarkm struct harvest *np; 226255071Smarkm 227255071Smarkm /* Initialise the harvest fifos */ 228256381Smarkm 229256381Smarkm /* Contains the currently unused event structs. */ 230255071Smarkm STAILQ_INIT(&emptyfifo.head); 231256381Smarkm for (i = 0; i < RANDOM_FIFO_MAX; i++) { 232255071Smarkm np = malloc(sizeof(struct harvest), M_ENTROPY, M_WAITOK); 233255071Smarkm STAILQ_INSERT_TAIL(&emptyfifo.head, np, next); 234255071Smarkm } 235256381Smarkm emptyfifo.count = RANDOM_FIFO_MAX; 236255071Smarkm 237256381Smarkm /* Will contain the queued-up events. */ 238256381Smarkm STAILQ_INIT(&harvestfifo.head); 239256381Smarkm harvestfifo.count = 0; 240256381Smarkm 241255071Smarkm mtx_init(&harvest_mtx, "entropy harvest mutex", NULL, MTX_SPIN); 242255071Smarkm 243295480Sjhb random_cb = cb; 244295480Sjhb} 245295480Sjhb 246295480Sjhbstatic void 247295480Sjhbrandom_harvestq_start_kproc(void *arg __unused) 248295480Sjhb{ 249295480Sjhb int error; 250295480Sjhb 251295480Sjhb if (random_cb == NULL) 252295480Sjhb return; 253295480Sjhb 254255071Smarkm /* Start the hash/reseed thread */ 255295480Sjhb error = kproc_create(random_kthread, random_cb, 256255071Smarkm &random_kthread_proc, RFHIGHPID, 0, "rand_harvestq"); /* RANDOM_CSPRNG_NAME */ 257255071Smarkm 258255071Smarkm if (error != 0) 259255071Smarkm panic("Cannot create entropy maintenance thread."); 260255071Smarkm} 261295480SjhbSYSINIT(random_kthread, SI_SUB_DRIVERS, SI_ORDER_ANY, 262295480Sjhb random_harvestq_start_kproc, NULL); 263255071Smarkm 264255071Smarkmvoid 265255071Smarkmrandom_harvestq_deinit(void) 266255071Smarkm{ 267255071Smarkm struct harvest *np; 268255071Smarkm 269255071Smarkm /* Destroy the harvest fifos */ 270255071Smarkm while (!STAILQ_EMPTY(&emptyfifo.head)) { 271255071Smarkm np = STAILQ_FIRST(&emptyfifo.head); 272255071Smarkm STAILQ_REMOVE_HEAD(&emptyfifo.head, next); 273255071Smarkm free(np, M_ENTROPY); 274255071Smarkm } 275256381Smarkm emptyfifo.count = 0; 276256381Smarkm while (!STAILQ_EMPTY(&harvestfifo.head)) { 277256381Smarkm np = STAILQ_FIRST(&harvestfifo.head); 278256381Smarkm STAILQ_REMOVE_HEAD(&harvestfifo.head, next); 279256381Smarkm free(np, M_ENTROPY); 280255071Smarkm } 281256381Smarkm harvestfifo.count = 0; 282255071Smarkm 283295480Sjhb /* 284295480Sjhb * Command the hash/reseed thread to end and wait for it to finish 285295480Sjhb */ 286295480Sjhb mtx_lock_spin(&harvest_mtx); 287295480Sjhb if (random_kthread_proc != NULL) { 288295480Sjhb random_kthread_control = -1; 289295480Sjhb msleep_spin((void *)&random_kthread_control, &harvest_mtx, 290295480Sjhb "term", 0); 291295480Sjhb } 292295480Sjhb mtx_unlock_spin(&harvest_mtx); 293295480Sjhb 294255071Smarkm mtx_destroy(&harvest_mtx); 295255071Smarkm} 296255071Smarkm 297255071Smarkm/* 298256381Smarkm * Entropy harvesting routine. 299256381Smarkm * This is supposed to be fast; do not do anything slow in here! 300256381Smarkm * 301256381Smarkm * It is also illegal (and morally reprehensible) to insert any 302256381Smarkm * high-rate data here. "High-rate" is define as a data source 303256381Smarkm * that will usually cause lots of failures of the "Lockless read" 304256381Smarkm * check a few lines below. This includes the "always-on" sources 305256381Smarkm * like the Intel "rdrand" or the VIA Nehamiah "xstore" sources. 306255071Smarkm */ 307255071Smarkmvoid 308255071Smarkmrandom_harvestq_internal(u_int64_t somecounter, const void *entropy, 309256381Smarkm u_int count, u_int bits, enum esource origin) 310255071Smarkm{ 311255071Smarkm struct harvest *event; 312255071Smarkm 313256381Smarkm KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, 314255071Smarkm ("random_harvest_internal: origin %d invalid\n", origin)); 315255071Smarkm 316255071Smarkm /* Lockless read to avoid lock operations if fifo is full. */ 317256381Smarkm if (harvestfifo.count >= RANDOM_FIFO_MAX) 318255071Smarkm return; 319255071Smarkm 320255071Smarkm mtx_lock_spin(&harvest_mtx); 321255071Smarkm 322255071Smarkm /* 323256381Smarkm * On't overfill the harvest queue; this could steal all 324256381Smarkm * our memory. 325255071Smarkm */ 326256381Smarkm if (harvestfifo.count < RANDOM_FIFO_MAX) { 327255071Smarkm event = STAILQ_FIRST(&emptyfifo.head); 328255071Smarkm if (event != NULL) { 329255071Smarkm /* Add the harvested data to the fifo */ 330255071Smarkm STAILQ_REMOVE_HEAD(&emptyfifo.head, next); 331256381Smarkm emptyfifo.count--; 332255071Smarkm event->somecounter = somecounter; 333255071Smarkm event->size = count; 334255071Smarkm event->bits = bits; 335255071Smarkm event->source = origin; 336255071Smarkm 337255071Smarkm /* XXXX Come back and make this dynamic! */ 338255071Smarkm count = MIN(count, HARVESTSIZE); 339255071Smarkm memcpy(event->entropy, entropy, count); 340255071Smarkm 341256381Smarkm STAILQ_INSERT_TAIL(&harvestfifo.head, 342255071Smarkm event, next); 343256381Smarkm harvestfifo.count++; 344255071Smarkm } 345255071Smarkm } 346256381Smarkm 347255071Smarkm mtx_unlock_spin(&harvest_mtx); 348255071Smarkm} 349