1 /*- 2 * Copyright (c) 2000-2014 Mark R V Murray 3 * Copyright (c) 2013 Arthur Mesh 4 * Copyright (c) 2004 Robert N. M. Watson 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer 12 * in this position and unchanged. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include "opt_random.h" 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/eventhandler.h> 38 #include <sys/kernel.h> 39 #include <sys/kthread.h> 40 #include <sys/linker.h> 41 #include <sys/lock.h> 42 #include <sys/malloc.h> 43 #include <sys/mutex.h> 44 #include <sys/random.h> 45 #include <sys/sbuf.h> 46 #include <sys/sysctl.h> 47 #include <sys/unistd.h> 48 49 #include <machine/cpu.h> 50 51 #include <dev/random/randomdev.h> 52 #include <dev/random/random_adaptors.h> 53 #include <dev/random/random_harvestq.h> 54 #include <dev/random/live_entropy_sources.h> 55 56 /* List for the dynamic sysctls */ 57 static struct sysctl_ctx_list random_clist; 58 59 /* 60 * How many events to queue up. We create this many items in 61 * an 'empty' queue, then transfer them to the 'harvest' queue with 62 * supplied junk. When used, they are transferred back to the 63 * 'empty' queue. 64 */ 65 #define RANDOM_FIFO_MAX 1024 66 67 /* 68 * The harvest mutex protects the consistency of the entropy Fifos and 69 * empty fifo and other associated structures. 70 */ 71 static struct mtx harvest_mtx; 72 73 /* 74 * Lockable FIFO ring buffer holding entropy events 75 * If ring_in == ring_out, 76 * the buffer is empty. 77 * If (ring_in + 1) == ring_out (MOD RANDOM_FIFO_MAX), 78 * the buffer is full. 79 * 80 * The ring_in variable needs locking as there are multiple 81 * sources to the ring. Only the sources may change ring_in, 82 * but the consumer may examine it. 83 * 84 * The ring_out variable does not need locking as there is 85 * only one consumer. Only the consumer may change ring_out, 86 * but the sources may examine it. 87 */ 88 static struct entropyfifo { 89 struct harvest_event ring[RANDOM_FIFO_MAX]; 90 volatile u_int ring_in; 91 volatile u_int ring_out; 92 } entropyfifo; 93 94 /* Round-robin destination cache. */ 95 u_int harvest_destination[ENTROPYSOURCE]; 96 97 /* Function called to process one harvested stochastic event */ 98 void (*harvest_process_event)(struct harvest_event *); 99 100 /* Allow the sysadmin to select the broad category of 101 * entropy types to harvest. 102 */ 103 static u_int harvest_source_mask = ((1U << RANDOM_ENVIRONMENTAL_END) - 1); 104 105 /* Pool count is used by anything needing to know how many entropy 106 * pools are currently being maintained. 107 * This is of use to (e.g.) the live source feed where we need to give 108 * all the pools a top-up. 109 */ 110 int harvest_pool_count; 111 112 /* <0 to end the kthread, 0 to let it run, 1 to flush the harvest queues */ 113 static int random_kthread_control = 0; 114 115 static struct proc *random_kthread_proc; 116 117 static void 118 random_kthread(void *arg __unused) 119 { 120 u_int maxloop, ring_out; 121 122 /* 123 * Process until told to stop. 124 * 125 * Locking is not needed as this is the only place we modify ring_out, and 126 * we only examine ring_in without changing it. Both of these are volatile, 127 * and this is a unique thread. 128 */ 129 while (random_kthread_control >= 0) { 130 131 /* Deal with events, if any. Restrict the number we do in one go. */ 132 maxloop = RANDOM_FIFO_MAX; 133 while (entropyfifo.ring_out != entropyfifo.ring_in) { 134 135 ring_out = (entropyfifo.ring_out + 1)%RANDOM_FIFO_MAX; 136 harvest_process_event(entropyfifo.ring + ring_out); 137 /* Modifying ring_out here ONLY. Sufficient for atomicity? */ 138 entropyfifo.ring_out = ring_out; 139 140 /* The ring may be filled quickly so don't loop forever. */ 141 if (--maxloop) 142 break; 143 144 } 145 146 /* 147 * Give the fast hardware sources a go 148 */ 149 live_entropy_sources_feed(); 150 151 /* 152 * If a queue flush was commanded, it has now happened, 153 * and we can mark this by resetting the command. 154 * A negative value, however, terminates the thread. 155 */ 156 157 if (random_kthread_control == 1) 158 random_kthread_control = 0; 159 160 /* Some work is done, so give the rest of the OS a chance. */ 161 tsleep_sbt(&random_kthread_control, 0, "-", SBT_1S/10, 0, C_PREL(1)); 162 163 } 164 165 randomdev_set_wakeup_exit(&random_kthread_control); 166 /* NOTREACHED */ 167 } 168 169 void 170 random_harvestq_flush(void) 171 { 172 173 /* Command a entropy queue flush and wait for it to finish */ 174 random_kthread_control = 1; 175 while (random_kthread_control) 176 pause("-", hz/10); 177 } 178 179 /* ARGSUSED */ 180 RANDOM_CHECK_UINT(harvestmask, 0, ((1U << RANDOM_ENVIRONMENTAL_END) - 1)); 181 182 /* ARGSUSED */ 183 static int 184 random_print_harvestmask(SYSCTL_HANDLER_ARGS) 185 { 186 struct sbuf sbuf; 187 int error, i; 188 189 error = sysctl_wire_old_buffer(req, 0); 190 if (error == 0) { 191 sbuf_new_for_sysctl(&sbuf, NULL, 128, req); 192 for (i = RANDOM_ENVIRONMENTAL_END - 1; i >= 0; i--) 193 sbuf_cat(&sbuf, (harvest_source_mask & (1U << i)) ? "1" : "0"); 194 error = sbuf_finish(&sbuf); 195 sbuf_delete(&sbuf); 196 } 197 198 return (error); 199 } 200 201 static const char *(random_source_descr[]) = { 202 "CACHED", 203 "ATTACH", 204 "KEYBOARD", 205 "MOUSE", 206 "NET_TUN", 207 "NET_ETHER", 208 "NET_NG", 209 "INTERRUPT", 210 "SWI", 211 "UMA_ALLOC", 212 "", /* "ENVIRONMENTAL_END" */ 213 "PURE_OCTEON", 214 "PURE_SAFE", 215 "PURE_GLXSB", 216 "PURE_UBSEC", 217 "PURE_HIFN", 218 "PURE_RDRAND", 219 "PURE_NEHEMIAH", 220 "PURE_RNDTEST", 221 /* "ENTROPYSOURCE" */ 222 }; 223 224 /* ARGSUSED */ 225 static int 226 random_print_harvestmask_symbolic(SYSCTL_HANDLER_ARGS) 227 { 228 struct sbuf sbuf; 229 int error, i; 230 231 error = sysctl_wire_old_buffer(req, 0); 232 if (error == 0) { 233 sbuf_new_for_sysctl(&sbuf, NULL, 128, req); 234 for (i = RANDOM_ENVIRONMENTAL_END - 1; i >= 0; i--) { 235 sbuf_cat(&sbuf, (i == RANDOM_ENVIRONMENTAL_END - 1) ? "" : ","); 236 sbuf_cat(&sbuf, (harvest_source_mask & (1U << i)) ? random_source_descr[i] : ""); 237 } 238 error = sbuf_finish(&sbuf); 239 sbuf_delete(&sbuf); 240 } 241 242 return (error); 243 } 244 245 void 246 random_harvestq_init(void (*event_processor)(struct harvest_event *), int poolcount) 247 { 248 uint8_t *keyfile, *data; 249 int error; 250 size_t size, j; 251 struct sysctl_oid *random_sys_o; 252 253 #ifdef RANDOM_DEBUG 254 printf("random: %s\n", __func__); 255 #endif 256 257 random_sys_o = SYSCTL_ADD_NODE(&random_clist, 258 SYSCTL_STATIC_CHILDREN(_kern_random), 259 OID_AUTO, "harvest", CTLFLAG_RW, 0, 260 "Entropy Device Parameters"); 261 262 SYSCTL_ADD_PROC(&random_clist, 263 SYSCTL_CHILDREN(random_sys_o), 264 OID_AUTO, "mask", CTLTYPE_UINT | CTLFLAG_RW, 265 &harvest_source_mask, ((1U << RANDOM_ENVIRONMENTAL_END) - 1), 266 random_check_uint_harvestmask, "IU", 267 "Entropy harvesting mask"); 268 269 SYSCTL_ADD_PROC(&random_clist, 270 SYSCTL_CHILDREN(random_sys_o), 271 OID_AUTO, "mask_bin", CTLTYPE_STRING | CTLFLAG_RD, 272 NULL, 0, random_print_harvestmask, "A", "Entropy harvesting mask (printable)"); 273 274 SYSCTL_ADD_PROC(&random_clist, 275 SYSCTL_CHILDREN(random_sys_o), 276 OID_AUTO, "mask_symbolic", CTLTYPE_STRING | CTLFLAG_RD, 277 NULL, 0, random_print_harvestmask_symbolic, "A", "Entropy harvesting mask (symbolic)"); 278 279 /* Point to the correct event_processing function */ 280 harvest_process_event = event_processor; 281 282 /* Store the pool count (used by live source feed) */ 283 harvest_pool_count = poolcount; 284 285 /* Initialise the harvesting mutex and in/out indexes. */ 286 mtx_init(&harvest_mtx, "entropy harvest mutex", NULL, MTX_SPIN); 287 entropyfifo.ring_in = entropyfifo.ring_out = 0U; 288 289 /* Start the hash/reseed thread */ 290 error = kproc_create(random_kthread, NULL, 291 &random_kthread_proc, RFHIGHPID, 0, "rand_harvestq"); 292 293 if (error != 0) 294 panic("Cannot create entropy maintenance thread."); 295 296 /* Get entropy that may have been preloaded by loader(8) 297 * and use it to pre-charge the entropy harvest queue. 298 */ 299 keyfile = preload_search_by_type("/boot/entropy"); 300 if (keyfile != NULL) { 301 data = preload_fetch_addr(keyfile); 302 size = preload_fetch_size(keyfile); 303 if (data != NULL && size != 0) { 304 for (j = 0; j < size; j += 16) 305 random_harvestq_internal(data + j, 16, 16, RANDOM_CACHED); 306 printf("random: read %zu bytes from preloaded cache\n", size); 307 bzero(data, size); 308 } 309 else 310 printf("random: no preloaded entropy cache\n"); 311 } 312 313 } 314 315 void 316 random_harvestq_deinit(void) 317 { 318 319 #ifdef RANDOM_DEBUG 320 printf("random: %s\n", __func__); 321 #endif 322 323 /* 324 * Command the hash/reseed thread to end and wait for it to finish 325 */ 326 random_kthread_control = -1; 327 tsleep(&random_kthread_control, 0, "term", 0); 328 329 mtx_destroy(&harvest_mtx); 330 331 sysctl_ctx_free(&random_clist); 332 } 333 334 /* 335 * Entropy harvesting routine. 336 * This is supposed to be fast; do not do anything slow in here! 337 * 338 * It is also illegal (and morally reprehensible) to insert any 339 * high-rate data here. "High-rate" is define as a data source 340 * that will usually cause lots of failures of the "Lockless read" 341 * check a few lines below. This includes the "always-on" sources 342 * like the Intel "rdrand" or the VIA Nehamiah "xstore" sources. 343 */ 344 /* XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle 345 * counters are built in, but on older hardware it will do a real time clock 346 * read which can be quite expensive. 347 */ 348 void 349 random_harvestq_internal(const void *entropy, u_int count, u_int bits, 350 enum random_entropy_source origin) 351 { 352 struct harvest_event *event; 353 u_int ring_in; 354 355 KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, 356 ("random_harvest_internal: origin %d invalid\n", origin)); 357 358 /* Mask out unwanted sources */ 359 if (!(harvest_source_mask & (1U << origin))) 360 return; 361 362 /* Lock ring_in against multi-thread contention */ 363 mtx_lock_spin(&harvest_mtx); 364 ring_in = (entropyfifo.ring_in + 1)%RANDOM_FIFO_MAX; 365 if (ring_in != entropyfifo.ring_out) { 366 /* The ring is not full */ 367 event = entropyfifo.ring + ring_in; 368 369 /* Stash the harvested stuff in the *event buffer */ 370 count = MIN(count, HARVESTSIZE); 371 event->he_somecounter = get_cyclecount(); 372 event->he_size = count; 373 event->he_bits = bits; 374 event->he_source = origin; 375 event->he_destination = harvest_destination[origin]++; 376 memcpy(event->he_entropy, entropy, count); 377 memset(event->he_entropy + count, 0, HARVESTSIZE - count); 378 379 entropyfifo.ring_in = ring_in; 380 } 381 mtx_unlock_spin(&harvest_mtx); 382 } 383