randomdev.c revision 91600
138465Smsmith/*- 2119482Sobrien * Copyright (c) 2000 Mark R V Murray 338465Smsmith * All rights reserved. 438465Smsmith * 5119482Sobrien * Redistribution and use in source and binary forms, with or without 638465Smsmith * modification, are permitted provided that the following conditions 738465Smsmith * are met: 838465Smsmith * 1. Redistributions of source code must retain the above copyright 938465Smsmith * notice, this list of conditions and the following disclaimer 1038465Smsmith * in this position and unchanged. 1138465Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1238465Smsmith * notice, this list of conditions and the following disclaimer in the 1338465Smsmith * documentation and/or other materials provided with the distribution. 1438465Smsmith * 1538465Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1638465Smsmith * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1738465Smsmith * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1838465Smsmith * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1938465Smsmith * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2038465Smsmith * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2138465Smsmith * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2238465Smsmith * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2338465Smsmith * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2438465Smsmith * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2538465Smsmith * 2638465Smsmith * $FreeBSD: head/sys/dev/random/randomdev.c 91600 2002-03-03 19:44:22Z markm $ 2738465Smsmith */ 2838465Smsmith 2938465Smsmith#include <sys/param.h> 3038465Smsmith#include <sys/systm.h> 3138465Smsmith#include <sys/bus.h> 3238465Smsmith#include <sys/conf.h> 3338465Smsmith#include <sys/fcntl.h> 3438465Smsmith#include <sys/filio.h> 3538465Smsmith#include <sys/kernel.h> 36119482Sobrien#include <sys/kthread.h> 37119482Sobrien#include <sys/lock.h> 38119482Sobrien#include <sys/malloc.h> 3938465Smsmith#include <sys/mutex.h> 4038465Smsmith#include <sys/poll.h> 4138465Smsmith#include <sys/proc.h> 4238465Smsmith#include <sys/random.h> 4338465Smsmith#include <sys/selinfo.h> 4438465Smsmith#include <sys/sysctl.h> 4538465Smsmith#include <sys/uio.h> 4638465Smsmith#include <sys/unistd.h> 4738465Smsmith#include <sys/vnode.h> 4838465Smsmith 4938465Smsmith#include <machine/bus.h> 5038465Smsmith#include <machine/cpu.h> 5138465Smsmith 5238465Smsmith#include <dev/random/randomdev.h> 5338465Smsmith 5438465Smsmithstatic d_open_t random_open; 5538465Smsmithstatic d_close_t random_close; 5638465Smsmithstatic d_read_t random_read; 5738465Smsmithstatic d_write_t random_write; 5838465Smsmithstatic d_ioctl_t random_ioctl; 5938465Smsmithstatic d_poll_t random_poll; 6038465Smsmith 6138465Smsmith#define CDEV_MAJOR 2 6238465Smsmith#define RANDOM_MINOR 3 6338465Smsmith 6438465Smsmithstatic struct cdevsw random_cdevsw = { 6538465Smsmith /* open */ random_open, 6638465Smsmith /* close */ random_close, 6738465Smsmith /* read */ random_read, 6838465Smsmith /* write */ random_write, 6938465Smsmith /* ioctl */ random_ioctl, 7038465Smsmith /* poll */ random_poll, 7138465Smsmith /* mmap */ nommap, 7238465Smsmith /* strategy */ nostrategy, 7338465Smsmith /* name */ "random", 7438465Smsmith /* maj */ CDEV_MAJOR, 7538465Smsmith /* dump */ nodump, 7638465Smsmith /* psize */ nopsize, 7738465Smsmith /* flags */ 0, 7838465Smsmith /* kqfilter */ NULL 7938465Smsmith}; 8038465Smsmith 81static void random_kthread(void *); 82static void random_harvest_internal(u_int64_t, void *, u_int, u_int, u_int, enum esource); 83static void random_write_internal(void *, int); 84 85/* Ring buffer holding harvested entropy */ 86static struct harvestring { 87 volatile u_int head; 88 volatile u_int tail; 89 struct harvest data[HARVEST_RING_SIZE]; 90} harvestring; 91 92static struct random_systat { 93 u_int seeded; /* 0 causes blocking 1 allows normal output */ 94 u_int burst; /* number of events to do before sleeping */ 95 struct selinfo rsel; /* For poll(2) */ 96} random_systat; 97 98/* <0 to end the kthread, 0 to let it run */ 99static int random_kthread_control = 0; 100 101static struct proc *random_kthread_proc; 102 103/* For use with make_dev(9)/destroy_dev(9). */ 104static dev_t random_dev; 105static dev_t urandom_dev; 106 107/* ARGSUSED */ 108static int 109random_check_boolean(SYSCTL_HANDLER_ARGS) 110{ 111 if (oidp->oid_arg1 != NULL && *(u_int *)(oidp->oid_arg1) != 0) 112 *(u_int *)(oidp->oid_arg1) = 1; 113 return sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); 114} 115 116RANDOM_CHECK_UINT(burst, 0, 20); 117 118SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 119 0, "Random Number Generator"); 120SYSCTL_NODE(_kern_random, OID_AUTO, sys, CTLFLAG_RW, 121 0, "Entropy Device Parameters"); 122SYSCTL_PROC(_kern_random_sys, OID_AUTO, seeded, 123 CTLTYPE_INT|CTLFLAG_RW, &random_systat.seeded, 1, 124 random_check_boolean, "I", "Seeded State"); 125SYSCTL_PROC(_kern_random_sys, OID_AUTO, burst, 126 CTLTYPE_INT|CTLFLAG_RW, &random_systat.burst, 20, 127 random_check_uint_burst, "I", "Harvest Burst Size"); 128SYSCTL_NODE(_kern_random_sys, OID_AUTO, harvest, CTLFLAG_RW, 129 0, "Entropy Sources"); 130SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, ethernet, 131 CTLTYPE_INT|CTLFLAG_RW, &harvest.ethernet, 0, 132 random_check_boolean, "I", "Harvest NIC entropy"); 133SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, point_to_point, 134 CTLTYPE_INT|CTLFLAG_RW, &harvest.point_to_point, 0, 135 random_check_boolean, "I", "Harvest serial net entropy"); 136SYSCTL_PROC(_kern_random_sys_harvest, OID_AUTO, interrupt, 137 CTLTYPE_INT|CTLFLAG_RW, &harvest.interrupt, 0, 138 random_check_boolean, "I", "Harvest IRQ entropy"); 139 140/* ARGSUSED */ 141static int 142random_open(dev_t dev __unused, int flags, int fmt __unused, struct thread *td) 143{ 144 int error; 145 146 if (flags & FWRITE) { 147 error = suser(td->td_proc); 148 if (error) 149 return (error); 150 error = securelevel_gt(td->td_ucred, 0); 151 if (error) 152 return (error); 153 } 154 return 0; 155} 156 157/* ARGSUSED */ 158static int 159random_close(dev_t dev __unused, int flags, int fmt __unused, struct thread *td) 160{ 161 if (flags & FWRITE) { 162 if (!(suser(td->td_proc) || 163 securelevel_gt(td->td_ucred, 0))) 164 random_reseed(); 165 } 166 return 0; 167} 168 169/* ARGSUSED */ 170static int 171random_read(dev_t dev __unused, struct uio *uio, int flag) 172{ 173 int c, ret; 174 int error = 0; 175 void *random_buf; 176 177 while (!random_systat.seeded) { 178 if (flag & IO_NDELAY) 179 error = EWOULDBLOCK; 180 else 181 error = tsleep(&random_systat, PUSER|PCATCH, 182 "block", 0); 183 if (error != 0) 184 return error; 185 } 186 c = uio->uio_resid < PAGE_SIZE ? uio->uio_resid : PAGE_SIZE; 187 random_buf = (void *)malloc((u_long)c, M_TEMP, M_WAITOK); 188 while (uio->uio_resid > 0 && error == 0) { 189 ret = read_random_real(random_buf, c); 190 error = uiomove(random_buf, ret, uio); 191 } 192 free(random_buf, M_TEMP); 193 return error; 194} 195 196/* ARGSUSED */ 197static int 198random_write(dev_t dev __unused, struct uio *uio, int flag __unused) 199{ 200 int c; 201 int error; 202 void *random_buf; 203 204 error = 0; 205 random_buf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 206 while (uio->uio_resid > 0) { 207 c = (int)(uio->uio_resid < PAGE_SIZE 208 ? uio->uio_resid 209 : PAGE_SIZE); 210 error = uiomove(random_buf, c, uio); 211 if (error) 212 break; 213 random_write_internal(random_buf, c); 214 } 215 free(random_buf, M_TEMP); 216 return error; 217} 218 219/* ARGSUSED */ 220static int 221random_ioctl(dev_t dev __unused, u_long cmd, caddr_t addr __unused, 222 int flags __unused, struct thread *td __unused) 223{ 224 switch (cmd) { 225 /* Really handled in upper layer */ 226 case FIOASYNC: 227 case FIONBIO: 228 return 0; 229 default: 230 return ENOTTY; 231 } 232} 233 234/* ARGSUSED */ 235static int 236random_poll(dev_t dev __unused, int events, struct thread *td) 237{ 238 int revents; 239 240 revents = 0; 241 if (events & (POLLIN | POLLRDNORM)) { 242 if (random_systat.seeded) 243 revents = events & (POLLIN | POLLRDNORM); 244 else 245 selrecord(td, &random_systat.rsel); 246 } 247 return revents; 248} 249 250/* ARGSUSED */ 251static int 252random_modevent(module_t mod __unused, int type, void *data __unused) 253{ 254 int error; 255 256 switch(type) { 257 case MOD_LOAD: 258 random_init(); 259 260 /* This can be turned off by the very paranoid 261 * a reseed will turn it back on. 262 */ 263 random_systat.seeded = 1; 264 265 /* Number of envents to process off the harvest 266 * queue before giving it a break and sleeping 267 */ 268 random_systat.burst = 20; 269 270 /* Initialise the harvest ringbuffer */ 271 harvestring.head = 0; 272 harvestring.tail = 0; 273 274 if (bootverbose) 275 printf("random: <entropy source>\n"); 276 random_dev = make_dev(&random_cdevsw, RANDOM_MINOR, UID_ROOT, 277 GID_WHEEL, 0666, "random"); 278 urandom_dev = make_dev_alias(random_dev, "urandom"); 279 280 /* Start the hash/reseed thread */ 281 error = kthread_create(random_kthread, NULL, 282 &random_kthread_proc, RFHIGHPID, "random"); 283 if (error != 0) 284 return error; 285 286 /* Register the randomness harvesting routine */ 287 random_init_harvester(random_harvest_internal, 288 read_random_real); 289 290 return 0; 291 292 case MOD_UNLOAD: 293 /* Deregister the randomness harvesting routine */ 294 random_deinit_harvester(); 295 296 /* Command the hash/reseed thread to end and 297 * wait for it to finish 298 */ 299 random_kthread_control = -1; 300 tsleep((void *)&random_kthread_control, PUSER, "term", 0); 301 302 random_deinit(); 303 304 destroy_dev(random_dev); 305 destroy_dev(urandom_dev); 306 return 0; 307 308 case MOD_SHUTDOWN: 309 return 0; 310 311 default: 312 return EOPNOTSUPP; 313 } 314} 315 316DEV_MODULE(random, random_modevent, NULL); 317 318/* ARGSUSED */ 319static void 320random_kthread(void *arg __unused) 321{ 322 struct harvest *event; 323 u_int newtail, burst; 324 325 /* Drain the harvest queue (in 'burst' size chunks, 326 * if 'burst' > 0. If 'burst' == 0, then completely 327 * drain the queue. 328 */ 329 for (burst = 0; ; burst++) { 330 331 if ((harvestring.tail == harvestring.head) || 332 (random_systat.burst && burst == random_systat.burst)) { 333 tsleep(&harvestring, PUSER, "sleep", hz/10); 334 burst = 0; 335 336 } 337 else { 338 339 /* Suck a harvested entropy event out of the queue and 340 * hand it to the event processor 341 */ 342 343 newtail = (harvestring.tail + 1) & HARVEST_RING_MASK; 344 event = &harvestring.data[harvestring.tail]; 345 346 /* Bump the ring counter. This action is assumed 347 * to be atomic. 348 */ 349 harvestring.tail = newtail; 350 351 random_process_event(event); 352 353 } 354 355 /* Is the thread scheduled for a shutdown? */ 356 if (random_kthread_control != 0) { 357#ifdef DEBUG 358 mtx_lock(&Giant); 359 printf("Random kthread setting terminate\n"); 360 mtx_unlock(&Giant); 361#endif 362 random_set_wakeup_exit(&random_kthread_control); 363 /* NOTREACHED */ 364 break; 365 } 366 367 } 368 369} 370 371/* Entropy harvesting routine. This is supposed to be fast; do 372 * not do anything slow in here! 373 */ 374static void 375random_harvest_internal(u_int64_t somecounter, void *entropy, u_int count, 376 u_int bits, u_int frac, enum esource origin) 377{ 378 struct harvest *pharvest; 379 u_int newhead; 380 381 newhead = (harvestring.head + 1) & HARVEST_RING_MASK; 382 383 if (newhead != harvestring.tail) { 384 385 /* Add the harvested data to the ring buffer */ 386 387 pharvest = &harvestring.data[harvestring.head]; 388 389 /* Stuff the harvested data into the ring */ 390 pharvest->somecounter = somecounter; 391 count = count > HARVESTSIZE ? HARVESTSIZE : count; 392 memcpy(pharvest->entropy, entropy, count); 393 pharvest->size = count; 394 pharvest->bits = bits; 395 pharvest->frac = frac; 396 pharvest->source = 397 origin < ENTROPYSOURCE ? origin : RANDOM_START; 398 399 /* Bump the ring counter. This action is assumed 400 * to be atomic. 401 */ 402 harvestring.head = newhead; 403 404 } 405 406} 407 408static void 409random_write_internal(void *buf, int count) 410{ 411 int i; 412 413 /* Break the input up into HARVESTSIZE chunks. 414 * The writer has too much control here, so "estimate" the 415 * the entropy as zero. 416 */ 417 for (i = 0; i < count; i += HARVESTSIZE) { 418 random_harvest_internal(get_cyclecount(), (char *)buf + i, 419 HARVESTSIZE, 0, 0, RANDOM_WRITE); 420 } 421 422 /* Maybe the loop iterated at least once */ 423 if (i > count) 424 i -= HARVESTSIZE; 425 426 /* Get the last bytes even if the input length is not 427 * a multiple of HARVESTSIZE. 428 */ 429 count %= HARVESTSIZE; 430 if (count) { 431 random_harvest_internal(get_cyclecount(), (char *)buf + i, 432 (u_int)count, 0, 0, RANDOM_WRITE); 433 } 434} 435 436void 437random_unblock(void) 438{ 439 if (!random_systat.seeded) { 440 random_systat.seeded = 1; 441 selwakeup(&random_systat.rsel); 442 wakeup(&random_systat); 443 } 444} 445