live_entropy_sources.c revision 256381
1212793Sdim/*- 2212793Sdim * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com> 3212793Sdim * Copyright (c) 2013 Mark R V Murray 4212793Sdim * All rights reserved. 5212793Sdim * 6212793Sdim * Redistribution and use in source and binary forms, with or without 7212793Sdim * modification, are permitted provided that the following conditions 8212793Sdim * are met: 9212793Sdim * 1. Redistributions of source code must retain the above copyright 10212793Sdim * notice, this list of conditions and the following disclaimer 11212793Sdim * in this position and unchanged. 12212793Sdim * 2. Redistributions in binary form must reproduce the above copyright 13212793Sdim * notice, this list of conditions and the following disclaimer in the 14212793Sdim * documentation and/or other materials provided with the distribution. 15218893Sdim * 16212793Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17221345Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18212793Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19234353Sdim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20218893Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21212793Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22226633Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23212793Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24249423Sdim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25212793Sdim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26212793Sdim */ 27212793Sdim 28212793Sdim#include <sys/param.h> 29212793Sdim__FBSDID("$FreeBSD: stable/10/sys/dev/random/live_entropy_sources.c 256381 2013-10-12 15:31:36Z markm $"); 30212793Sdim 31212793Sdim#include <sys/kernel.h> 32221345Sdim#include <sys/libkern.h> 33221345Sdim#include <sys/lock.h> 34223017Sdim#include <sys/malloc.h> 35223017Sdim#include <sys/queue.h> 36223017Sdim#include <sys/random.h> 37212793Sdim#include <sys/selinfo.h> 38212793Sdim#include <sys/sx.h> 39212793Sdim#include <sys/sysctl.h> 40212793Sdim#include <sys/systm.h> 41212793Sdim#include <sys/unistd.h> 42218893Sdim 43212793Sdim#include <machine/cpu.h> 44212793Sdim 45218893Sdim#include <dev/random/randomdev.h> 46218893Sdim#include <dev/random/randomdev_soft.h> 47218893Sdim#include <dev/random/random_adaptors.h> 48218893Sdim#include <dev/random/random_harvestq.h> 49218893Sdim 50221345Sdim#include "live_entropy_sources.h" 51221345Sdim 52212793SdimLIST_HEAD(les_head, live_entropy_sources); 53212793Sdimstatic struct les_head sources = LIST_HEAD_INITIALIZER(sources); 54218893Sdim 55221345Sdim/* 56221345Sdim * The live_lock protects the consistency of the "struct les_head sources" 57218893Sdim */ 58223017Sdimstatic struct sx les_lock; /* need a sleepable lock */ 59212793Sdim 60212793Sdimvoid 61221345Sdimlive_entropy_source_register(struct random_hardware_source *rsource) 62221345Sdim{ 63221345Sdim struct live_entropy_sources *les; 64221345Sdim 65234353Sdim KASSERT(rsource != NULL, ("invalid input to %s", __func__)); 66221345Sdim 67221345Sdim les = malloc(sizeof(struct live_entropy_sources), M_ENTROPY, M_WAITOK); 68221345Sdim les->rsource = rsource; 69221345Sdim 70221345Sdim sx_xlock(&les_lock); 71221345Sdim LIST_INSERT_HEAD(&sources, les, entries); 72234353Sdim sx_xunlock(&les_lock); 73221345Sdim} 74221345Sdim 75221345Sdimvoid 76221345Sdimlive_entropy_source_deregister(struct random_hardware_source *rsource) 77221345Sdim{ 78221345Sdim struct live_entropy_sources *les = NULL; 79221345Sdim 80221345Sdim KASSERT(rsource != NULL, ("invalid input to %s", __func__)); 81224145Sdim 82224145Sdim sx_xlock(&les_lock); 83224145Sdim LIST_FOREACH(les, &sources, entries) 84234353Sdim if (les->rsource == rsource) { 85221345Sdim LIST_REMOVE(les, entries); 86221345Sdim break; 87221345Sdim } 88224145Sdim sx_xunlock(&les_lock); 89221345Sdim if (les != NULL) 90221345Sdim free(les, M_ENTROPY); 91221345Sdim} 92221345Sdim 93234353Sdimstatic int 94221345Sdimlive_entropy_source_handler(SYSCTL_HANDLER_ARGS) 95234353Sdim{ 96234353Sdim struct live_entropy_sources *les; 97234353Sdim int error, count; 98234353Sdim 99234353Sdim count = error = 0; 100234353Sdim 101234353Sdim sx_slock(&les_lock); 102234353Sdim 103234353Sdim if (LIST_EMPTY(&sources)) 104234353Sdim error = SYSCTL_OUT(req, "", 0); 105234353Sdim else { 106234353Sdim LIST_FOREACH(les, &sources, entries) { 107234353Sdim 108234353Sdim error = SYSCTL_OUT(req, ",", count++ ? 1 : 0); 109234353Sdim if (error) 110234353Sdim break; 111212793Sdim 112212793Sdim error = SYSCTL_OUT(req, les->rsource->ident, strlen(les->rsource->ident)); 113234353Sdim if (error) 114234353Sdim break; 115234353Sdim } 116234353Sdim } 117234353Sdim 118234353Sdim sx_sunlock(&les_lock); 119234353Sdim 120234353Sdim return (error); 121218893Sdim} 122212793Sdim 123221345Sdimstatic void 124221345Sdimlive_entropy_sources_init(void *unused) 125221345Sdim{ 126221345Sdim 127221345Sdim SYSCTL_PROC(_kern_random, OID_AUTO, live_entropy_sources, 128221345Sdim CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 129221345Sdim NULL, 0, live_entropy_source_handler, "", 130221345Sdim "List of Active Live Entropy Sources"); 131221345Sdim 132221345Sdim sx_init(&les_lock, "live_entropy_sources"); 133218893Sdim} 134221345Sdim 135221345Sdim/* 136221345Sdim * Run through all "live" sources reading entropy for the given 137221345Sdim * number of rounds, which should be a multiple of the number 138234353Sdim * of entropy accumulation pools in use; 2 for Yarrow and 32 139221345Sdim * for Fortuna. 140221345Sdim * 141221345Sdim * BEWARE!!! 142221345Sdim * This function runs inside the RNG thread! Don't do anything silly! 143221345Sdim * Remember that we are NOT holding harvest_mtx on entry! 144221345Sdim */ 145221345Sdimvoid 146221345Sdimlive_entropy_sources_feed(int rounds, event_proc_f entropy_processor) 147221345Sdim{ 148221345Sdim static struct harvest event; 149221345Sdim static uint8_t buf[HARVESTSIZE]; 150221345Sdim struct live_entropy_sources *les; 151224145Sdim int i, n; 152223017Sdim 153223017Sdim sx_slock(&les_lock); 154221345Sdim 155221345Sdim /* 156221345Sdim * Walk over all of live entropy sources, and feed their output 157221345Sdim * to the system-wide RNG. 158221345Sdim */ 159221345Sdim LIST_FOREACH(les, &sources, entries) { 160221345Sdim 161221345Sdim for (i = 0; i < rounds; i++) { 162212793Sdim /* 163221345Sdim * This should be quick, since it's a live entropy 164221345Sdim * source. 165221345Sdim */ 166221345Sdim /* FIXME: Whine loudly if this didn't work. */ 167221345Sdim n = les->rsource->read(buf, sizeof(buf)); 168212793Sdim n = MIN(n, HARVESTSIZE); 169212793Sdim 170218893Sdim event.somecounter = get_cyclecount(); 171218893Sdim event.size = n; 172221345Sdim event.bits = (n*8)/2; 173221345Sdim event.source = les->rsource->source; 174223017Sdim memcpy(event.entropy, buf, n); 175218893Sdim 176221345Sdim /* Do the actual entropy insertion */ 177212793Sdim entropy_processor(&event); 178218893Sdim } 179218893Sdim 180212793Sdim } 181218893Sdim 182218893Sdim sx_sunlock(&les_lock); 183218893Sdim} 184212793Sdim 185218893Sdimstatic void 186218893Sdimlive_entropy_sources_deinit(void *unused) 187218893Sdim{ 188218893Sdim 189218893Sdim sx_destroy(&les_lock); 190218893Sdim} 191218893Sdim 192212793SdimSYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, 193223017Sdim live_entropy_sources_init, NULL); 194224145SdimSYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, 195223017Sdim live_entropy_sources_deinit, NULL); 196223017Sdim