1254147Sobrien/*- 2254147Sobrien * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com> 3254147Sobrien * Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org> 4256381Smarkm * Copyright (c) 2013 Mark R V Murray 5254147Sobrien * All rights reserved. 6254147Sobrien * 7254147Sobrien * Redistribution and use in source and binary forms, with or without 8254147Sobrien * modification, are permitted provided that the following conditions 9254147Sobrien * are met: 10254147Sobrien * 1. Redistributions of source code must retain the above copyright 11254147Sobrien * notice, this list of conditions and the following disclaimer 12254147Sobrien * in this position and unchanged. 13254147Sobrien * 2. Redistributions in binary form must reproduce the above copyright 14254147Sobrien * notice, this list of conditions and the following disclaimer in the 15254147Sobrien * documentation and/or other materials provided with the distribution. 16254147Sobrien * 17254147Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18254147Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19254147Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20254147Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21254147Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22254147Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23254147Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24254147Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25254147Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26254147Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27254147Sobrien */ 28254147Sobrien 29254147Sobrien#include <sys/param.h> 30254147Sobrien__FBSDID("$FreeBSD$"); 31254147Sobrien 32256381Smarkm#include <sys/systm.h> 33254147Sobrien#include <sys/kernel.h> 34255362Smarkm#include <sys/kthread.h> 35256381Smarkm#include <sys/libkern.h> 36254147Sobrien#include <sys/lock.h> 37256381Smarkm#include <sys/malloc.h> 38256381Smarkm#include <sys/queue.h> 39255362Smarkm#include <sys/random.h> 40254147Sobrien#include <sys/selinfo.h> 41256381Smarkm#include <sys/sx.h> 42254147Sobrien#include <sys/sysctl.h> 43255362Smarkm#include <sys/unistd.h> 44254147Sobrien 45255362Smarkm#include <dev/random/randomdev.h> 46255362Smarkm#include <dev/random/randomdev_soft.h> 47254147Sobrien#include <dev/random/random_adaptors.h> 48254147Sobrien 49254147SobrienLIST_HEAD(adaptors_head, random_adaptors); 50254147Sobrienstatic struct adaptors_head adaptors = LIST_HEAD_INITIALIZER(adaptors); 51254147Sobrienstatic struct sx adaptors_lock; /* need a sleepable lock */ 52254147Sobrien 53254147Sobrien/* List for the dynamic sysctls */ 54254147Sobrienstatic struct sysctl_ctx_list random_clist; 55254147Sobrien 56255379Smarkmstruct random_adaptor *random_adaptor; 57255379Smarkm 58256381SmarkmMALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); 59254147Sobrien 60254147Sobrienint 61254147Sobrienrandom_adaptor_register(const char *name, struct random_adaptor *rsp) 62254147Sobrien{ 63254147Sobrien struct random_adaptors *rpp; 64254147Sobrien 65254147Sobrien KASSERT(name != NULL && rsp != NULL, ("invalid input to %s", __func__)); 66254147Sobrien 67256381Smarkm rpp = malloc(sizeof(struct random_adaptors), M_ENTROPY, M_WAITOK); 68254147Sobrien rpp->name = name; 69254147Sobrien rpp->rsp = rsp; 70254147Sobrien 71254147Sobrien sx_xlock(&adaptors_lock); 72254147Sobrien LIST_INSERT_HEAD(&adaptors, rpp, entries); 73254147Sobrien sx_xunlock(&adaptors_lock); 74254147Sobrien 75254147Sobrien return (0); 76254147Sobrien} 77254147Sobrien 78254147Sobrienstruct random_adaptor * 79254147Sobrienrandom_adaptor_get(const char *name) 80254147Sobrien{ 81254147Sobrien struct random_adaptors *rpp; 82254147Sobrien struct random_adaptor *rsp; 83254147Sobrien 84254147Sobrien rsp = NULL; 85254147Sobrien 86254147Sobrien sx_slock(&adaptors_lock); 87254147Sobrien 88254147Sobrien LIST_FOREACH(rpp, &adaptors, entries) 89254147Sobrien if (strcmp(rpp->name, name) == 0) 90254147Sobrien rsp = rpp->rsp; 91254147Sobrien 92254147Sobrien sx_sunlock(&adaptors_lock); 93254147Sobrien 94254147Sobrien return (rsp); 95254147Sobrien} 96254147Sobrien 97255362Smarkm/* 98255362Smarkm * Walk a list of registered random(4) adaptors and pick the last non-selected 99255362Smarkm * one. 100255362Smarkm * 101255362Smarkm * If none are selected, use yarrow if available. 102255362Smarkm */ 103255362Smarkmvoid 104255362Smarkmrandom_adaptor_choose(struct random_adaptor **adaptor) 105255362Smarkm{ 106255362Smarkm char rngs[128], *token, *cp; 107256414Smarkm struct random_adaptors *rppi, *ramax; 108256414Smarkm unsigned primax; 109255362Smarkm 110255362Smarkm KASSERT(adaptor != NULL, ("pre-conditions failed")); 111255362Smarkm 112255362Smarkm *adaptor = NULL; 113256414Smarkm if (TUNABLE_STR_FETCH("kern.random.active_adaptor", rngs, sizeof(rngs))) { 114255362Smarkm cp = rngs; 115255362Smarkm 116256381Smarkm while ((token = strsep(&cp, ",")) != NULL) 117255362Smarkm if ((*adaptor = random_adaptor_get(token)) != NULL) 118255362Smarkm break; 119255362Smarkm else if (bootverbose) 120256381Smarkm printf("%s random adaptor is not available," 121256381Smarkm " skipping\n", token); 122255362Smarkm } 123255362Smarkm 124256414Smarkm primax = 0U; 125255362Smarkm if (*adaptor == NULL) { 126255362Smarkm /* 127256414Smarkm * Fall back to the highest priority item on the available 128256414Smarkm * RNG list. 129255362Smarkm */ 130256381Smarkm sx_slock(&adaptors_lock); 131255362Smarkm 132256414Smarkm ramax = NULL; 133256414Smarkm LIST_FOREACH(rppi, &adaptors, entries) { 134256414Smarkm if (rppi->rsp->priority >= primax) { 135256414Smarkm ramax = rppi; 136256414Smarkm primax = rppi->rsp->priority; 137256414Smarkm } 138256414Smarkm } 139256414Smarkm if (ramax != NULL) 140256414Smarkm *adaptor = ramax->rsp; 141255362Smarkm 142256381Smarkm sx_sunlock(&adaptors_lock); 143255362Smarkm 144255362Smarkm if (bootverbose && *adaptor) 145255391Smarkm printf("Falling back to <%s> random adaptor\n", 146255362Smarkm (*adaptor)->ident); 147255362Smarkm } 148255362Smarkm} 149255362Smarkm 150255362Smarkmstatic void 151254147Sobrienrandom_adaptors_deinit(void *unused) 152254147Sobrien{ 153254147Sobrien 154254147Sobrien sx_destroy(&adaptors_lock); 155254147Sobrien sysctl_ctx_free(&random_clist); 156254147Sobrien} 157254147Sobrien 158254147Sobrienstatic int 159254147Sobrienrandom_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS) 160254147Sobrien{ 161254147Sobrien struct random_adaptors *rpp; 162255362Smarkm int error, count; 163254147Sobrien 164255362Smarkm count = error = 0; 165254147Sobrien 166254147Sobrien sx_slock(&adaptors_lock); 167254147Sobrien 168256381Smarkm if (LIST_EMPTY(&adaptors)) 169255362Smarkm error = SYSCTL_OUT(req, "", 0); 170256381Smarkm else { 171255362Smarkm LIST_FOREACH(rpp, &adaptors, entries) { 172255362Smarkm 173255362Smarkm error = SYSCTL_OUT(req, ",", count++ ? 1 : 0); 174255362Smarkm if (error) 175255362Smarkm break; 176255362Smarkm 177255362Smarkm error = SYSCTL_OUT(req, rpp->name, strlen(rpp->name)); 178255362Smarkm if (error) 179255362Smarkm break; 180255362Smarkm } 181254147Sobrien } 182254147Sobrien 183254147Sobrien sx_sunlock(&adaptors_lock); 184254147Sobrien 185254147Sobrien return (error); 186254147Sobrien} 187254147Sobrien 188255362Smarkmstatic int 189255362Smarkmrandom_sysctl_active_adaptor_handler(SYSCTL_HANDLER_ARGS) 190255362Smarkm{ 191255362Smarkm struct random_adaptor *rsp; 192255362Smarkm struct random_adaptors *rpp; 193255362Smarkm const char *name; 194255362Smarkm int error; 195255362Smarkm 196255362Smarkm name = NULL; 197255379Smarkm rsp = random_adaptor; 198255362Smarkm 199255362Smarkm if (rsp != NULL) { 200255362Smarkm sx_slock(&adaptors_lock); 201255362Smarkm 202256381Smarkm LIST_FOREACH(rpp, &adaptors, entries) 203255362Smarkm if (rpp->rsp == rsp) 204255362Smarkm name = rpp->name; 205255362Smarkm 206255362Smarkm sx_sunlock(&adaptors_lock); 207255362Smarkm } 208255362Smarkm 209256381Smarkm if (rsp == NULL || name == NULL) 210255362Smarkm error = SYSCTL_OUT(req, "", 0); 211256381Smarkm else 212255362Smarkm error = SYSCTL_OUT(req, name, strlen(name)); 213255362Smarkm 214255362Smarkm return (error); 215255362Smarkm} 216255362Smarkm 217254147Sobrienstatic void 218254147Sobrienrandom_adaptors_init(void *unused) 219254147Sobrien{ 220254147Sobrien 221254147Sobrien SYSCTL_PROC(_kern_random, OID_AUTO, adaptors, 222254147Sobrien CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 223254147Sobrien NULL, 0, random_sysctl_adaptors_handler, "", 224254147Sobrien "Random Number Generator adaptors"); 225254147Sobrien 226255362Smarkm SYSCTL_PROC(_kern_random, OID_AUTO, active_adaptor, 227255362Smarkm CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 228255362Smarkm NULL, 0, random_sysctl_active_adaptor_handler, "", 229255362Smarkm "Active Random Number Generator Adaptor"); 230255362Smarkm 231254147Sobrien sx_init(&adaptors_lock, "random_adaptors"); 232254147Sobrien} 233254147Sobrien 234254147SobrienSYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Random Number Generator"); 235254147Sobrien 236295480SjhbSYSINIT(random_adaptors, SI_SUB_RANDOM, SI_ORDER_FIRST, random_adaptors_init, 237254147Sobrien NULL); 238295480SjhbSYSUNINIT(random_adaptors, SI_SUB_RANDOM, SI_ORDER_FIRST, 239254147Sobrien random_adaptors_deinit, NULL); 240256381Smarkm 241256381Smarkmstatic void 242256381Smarkmrandom_adaptors_reseed(void *unused) 243256381Smarkm{ 244256381Smarkm 245256381Smarkm (void)unused; 246256381Smarkm if (random_adaptor != NULL) 247256381Smarkm (*random_adaptor->reseed)(); 248256381Smarkm arc4rand(NULL, 0, 1); 249256381Smarkm} 250256381SmarkmSYSINIT(random_reseed, SI_SUB_INTRINSIC_POST, SI_ORDER_SECOND, 251256381Smarkm random_adaptors_reseed, NULL); 252