1256381Smarkm/*- 2256381Smarkm * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com> 3256381Smarkm * Copyright (c) 2013 Mark R V Murray 4256381Smarkm * All rights reserved. 5256381Smarkm * 6256381Smarkm * Redistribution and use in source and binary forms, with or without 7256381Smarkm * modification, are permitted provided that the following conditions 8256381Smarkm * are met: 9256381Smarkm * 1. Redistributions of source code must retain the above copyright 10256381Smarkm * notice, this list of conditions and the following disclaimer 11256381Smarkm * in this position and unchanged. 12256381Smarkm * 2. Redistributions in binary form must reproduce the above copyright 13256381Smarkm * notice, this list of conditions and the following disclaimer in the 14256381Smarkm * documentation and/or other materials provided with the distribution. 15256381Smarkm * 16256381Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17256381Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18256381Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19256381Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20256381Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21256381Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22256381Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23256381Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24256381Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25256381Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26256381Smarkm */ 27256381Smarkm 28256381Smarkm#include <sys/param.h> 29256381Smarkm__FBSDID("$FreeBSD$"); 30256381Smarkm 31256381Smarkm#include <sys/kernel.h> 32256381Smarkm#include <sys/libkern.h> 33256381Smarkm#include <sys/lock.h> 34256381Smarkm#include <sys/malloc.h> 35256381Smarkm#include <sys/queue.h> 36256381Smarkm#include <sys/random.h> 37256381Smarkm#include <sys/selinfo.h> 38256381Smarkm#include <sys/sx.h> 39256381Smarkm#include <sys/sysctl.h> 40256381Smarkm#include <sys/systm.h> 41256381Smarkm#include <sys/unistd.h> 42256381Smarkm 43256381Smarkm#include <machine/cpu.h> 44256381Smarkm 45256381Smarkm#include <dev/random/randomdev.h> 46256381Smarkm#include <dev/random/randomdev_soft.h> 47256381Smarkm#include <dev/random/random_adaptors.h> 48256381Smarkm#include <dev/random/random_harvestq.h> 49256381Smarkm 50256381Smarkm#include "live_entropy_sources.h" 51256381Smarkm 52256381SmarkmLIST_HEAD(les_head, live_entropy_sources); 53256381Smarkmstatic struct les_head sources = LIST_HEAD_INITIALIZER(sources); 54256381Smarkm 55256381Smarkm/* 56256381Smarkm * The live_lock protects the consistency of the "struct les_head sources" 57256381Smarkm */ 58256381Smarkmstatic struct sx les_lock; /* need a sleepable lock */ 59256381Smarkm 60256381Smarkmvoid 61256381Smarkmlive_entropy_source_register(struct random_hardware_source *rsource) 62256381Smarkm{ 63256381Smarkm struct live_entropy_sources *les; 64256381Smarkm 65256381Smarkm KASSERT(rsource != NULL, ("invalid input to %s", __func__)); 66256381Smarkm 67256381Smarkm les = malloc(sizeof(struct live_entropy_sources), M_ENTROPY, M_WAITOK); 68256381Smarkm les->rsource = rsource; 69256381Smarkm 70256381Smarkm sx_xlock(&les_lock); 71256381Smarkm LIST_INSERT_HEAD(&sources, les, entries); 72256381Smarkm sx_xunlock(&les_lock); 73256381Smarkm} 74256381Smarkm 75256381Smarkmvoid 76256381Smarkmlive_entropy_source_deregister(struct random_hardware_source *rsource) 77256381Smarkm{ 78256381Smarkm struct live_entropy_sources *les = NULL; 79256381Smarkm 80256381Smarkm KASSERT(rsource != NULL, ("invalid input to %s", __func__)); 81256381Smarkm 82256381Smarkm sx_xlock(&les_lock); 83256381Smarkm LIST_FOREACH(les, &sources, entries) 84256381Smarkm if (les->rsource == rsource) { 85256381Smarkm LIST_REMOVE(les, entries); 86256381Smarkm break; 87256381Smarkm } 88256381Smarkm sx_xunlock(&les_lock); 89256381Smarkm if (les != NULL) 90256381Smarkm free(les, M_ENTROPY); 91256381Smarkm} 92256381Smarkm 93256381Smarkmstatic int 94256381Smarkmlive_entropy_source_handler(SYSCTL_HANDLER_ARGS) 95256381Smarkm{ 96256381Smarkm struct live_entropy_sources *les; 97256381Smarkm int error, count; 98256381Smarkm 99256381Smarkm count = error = 0; 100256381Smarkm 101256381Smarkm sx_slock(&les_lock); 102256381Smarkm 103256381Smarkm if (LIST_EMPTY(&sources)) 104256381Smarkm error = SYSCTL_OUT(req, "", 0); 105256381Smarkm else { 106256381Smarkm LIST_FOREACH(les, &sources, entries) { 107256381Smarkm 108256381Smarkm error = SYSCTL_OUT(req, ",", count++ ? 1 : 0); 109256381Smarkm if (error) 110256381Smarkm break; 111256381Smarkm 112256381Smarkm error = SYSCTL_OUT(req, les->rsource->ident, strlen(les->rsource->ident)); 113256381Smarkm if (error) 114256381Smarkm break; 115256381Smarkm } 116256381Smarkm } 117256381Smarkm 118256381Smarkm sx_sunlock(&les_lock); 119256381Smarkm 120256381Smarkm return (error); 121256381Smarkm} 122256381Smarkm 123256381Smarkmstatic void 124256381Smarkmlive_entropy_sources_init(void *unused) 125256381Smarkm{ 126256381Smarkm 127256381Smarkm SYSCTL_PROC(_kern_random, OID_AUTO, live_entropy_sources, 128256381Smarkm CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 129256381Smarkm NULL, 0, live_entropy_source_handler, "", 130256381Smarkm "List of Active Live Entropy Sources"); 131256381Smarkm 132256381Smarkm sx_init(&les_lock, "live_entropy_sources"); 133256381Smarkm} 134256381Smarkm 135256381Smarkm/* 136256381Smarkm * Run through all "live" sources reading entropy for the given 137256381Smarkm * number of rounds, which should be a multiple of the number 138256381Smarkm * of entropy accumulation pools in use; 2 for Yarrow and 32 139256381Smarkm * for Fortuna. 140256381Smarkm * 141256381Smarkm * BEWARE!!! 142256381Smarkm * This function runs inside the RNG thread! Don't do anything silly! 143256381Smarkm * Remember that we are NOT holding harvest_mtx on entry! 144256381Smarkm */ 145256381Smarkmvoid 146256381Smarkmlive_entropy_sources_feed(int rounds, event_proc_f entropy_processor) 147256381Smarkm{ 148256381Smarkm static struct harvest event; 149256381Smarkm static uint8_t buf[HARVESTSIZE]; 150256381Smarkm struct live_entropy_sources *les; 151256381Smarkm int i, n; 152256381Smarkm 153256381Smarkm sx_slock(&les_lock); 154256381Smarkm 155256381Smarkm /* 156256381Smarkm * Walk over all of live entropy sources, and feed their output 157256381Smarkm * to the system-wide RNG. 158256381Smarkm */ 159256381Smarkm LIST_FOREACH(les, &sources, entries) { 160256381Smarkm 161256381Smarkm for (i = 0; i < rounds; i++) { 162256381Smarkm /* 163256381Smarkm * This should be quick, since it's a live entropy 164256381Smarkm * source. 165256381Smarkm */ 166256381Smarkm /* FIXME: Whine loudly if this didn't work. */ 167256381Smarkm n = les->rsource->read(buf, sizeof(buf)); 168256381Smarkm n = MIN(n, HARVESTSIZE); 169256381Smarkm 170256381Smarkm event.somecounter = get_cyclecount(); 171256381Smarkm event.size = n; 172256381Smarkm event.bits = (n*8)/2; 173256381Smarkm event.source = les->rsource->source; 174256381Smarkm memcpy(event.entropy, buf, n); 175256381Smarkm 176256381Smarkm /* Do the actual entropy insertion */ 177256381Smarkm entropy_processor(&event); 178256381Smarkm } 179256381Smarkm 180256381Smarkm } 181256381Smarkm 182256381Smarkm sx_sunlock(&les_lock); 183256381Smarkm} 184256381Smarkm 185256381Smarkmstatic void 186256381Smarkmlive_entropy_sources_deinit(void *unused) 187256381Smarkm{ 188256381Smarkm 189256381Smarkm sx_destroy(&les_lock); 190256381Smarkm} 191256381Smarkm 192256381SmarkmSYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, 193256381Smarkm live_entropy_sources_init, NULL); 194256381SmarkmSYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, 195256381Smarkm live_entropy_sources_deinit, NULL); 196