2 * Copyright (c) 2000-2014 Mark R V Murray
3 * Copyright (c) 2013 Arthur Mesh
4 * Copyright (c) 2004 Robert N. M. Watson
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include "opt_random.h"
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>
42 #include <sys/malloc.h>
43 #include <sys/mutex.h>
44 #include <sys/random.h>
46 #include <sys/sysctl.h>
47 #include <sys/unistd.h>
49 #include <machine/cpu.h>
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>
56 /* List for the dynamic sysctls */
57 static struct sysctl_ctx_list random_clist;
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
65 #define RANDOM_FIFO_MAX 1024
68 * The harvest mutex protects the consistency of the entropy Fifos and
69 * empty fifo and other associated structures.
71 static struct mtx harvest_mtx;
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),
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.
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.
88 static struct entropyfifo {
89 struct harvest_event ring[RANDOM_FIFO_MAX];
90 volatile u_int ring_in;
91 volatile u_int ring_out;
94 /* Round-robin destination cache. */
95 u_int harvest_destination[ENTROPYSOURCE];
97 /* Function called to process one harvested stochastic event */
98 void (*harvest_process_event)(struct harvest_event *);
100 /* Allow the sysadmin to select the broad category of
101 * entropy types to harvest.
103 static u_int harvest_source_mask = ((1U << RANDOM_ENVIRONMENTAL_END) - 1);
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.
110 int harvest_pool_count;
112 /* <0 to end the kthread, 0 to let it run, 1 to flush the harvest queues */
113 static int random_kthread_control = 0;
115 static struct proc *random_kthread_proc;
118 random_kthread(void *arg __unused)
120 u_int maxloop, ring_out;
123 * Process until told to stop.
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.
129 while (random_kthread_control >= 0) {
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) {
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;
140 /* The ring may be filled quickly so don't loop forever. */
147 * Give the fast hardware sources a go
149 live_entropy_sources_feed();
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.
157 if (random_kthread_control == 1)
158 random_kthread_control = 0;
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));
165 randomdev_set_wakeup_exit(&random_kthread_control);
170 random_harvestq_flush(void)
173 /* Command a entropy queue flush and wait for it to finish */
174 random_kthread_control = 1;
175 while (random_kthread_control)
180 RANDOM_CHECK_UINT(harvestmask, 0, ((1U << RANDOM_ENVIRONMENTAL_END) - 1));
184 random_print_harvestmask(SYSCTL_HANDLER_ARGS)
189 error = sysctl_wire_old_buffer(req, 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);
201 static const char *(random_source_descr[]) = {
212 "", /* "ENVIRONMENTAL_END" */
221 /* "ENTROPYSOURCE" */
226 random_print_harvestmask_symbolic(SYSCTL_HANDLER_ARGS)
231 error = sysctl_wire_old_buffer(req, 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] : "");
238 error = sbuf_finish(&sbuf);
246 random_harvestq_init(void (*event_processor)(struct harvest_event *), int poolcount)
248 uint8_t *keyfile, *data;
251 struct sysctl_oid *random_sys_o;
254 printf("random: %s\n", __func__);
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");
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");
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)");
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)");
279 /* Point to the correct event_processing function */
280 harvest_process_event = event_processor;
282 /* Store the pool count (used by live source feed) */
283 harvest_pool_count = poolcount;
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;
289 /* Start the hash/reseed thread */
290 error = kproc_create(random_kthread, NULL,
291 &random_kthread_proc, RFHIGHPID, 0, "rand_harvestq");
294 panic("Cannot create entropy maintenance thread.");
296 /* Get entropy that may have been preloaded by loader(8)
297 * and use it to pre-charge the entropy harvest queue.
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);
310 printf("random: no preloaded entropy cache\n");
316 random_harvestq_deinit(void)
320 printf("random: %s\n", __func__);
324 * Command the hash/reseed thread to end and wait for it to finish
326 random_kthread_control = -1;
327 tsleep(&random_kthread_control, 0, "term", 0);
329 mtx_destroy(&harvest_mtx);
331 sysctl_ctx_free(&random_clist);
335 * Entropy harvesting routine.
336 * This is supposed to be fast; do not do anything slow in here!
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.
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.
349 random_harvestq_internal(const void *entropy, u_int count, u_int bits,
350 enum random_entropy_source origin)
352 struct harvest_event *event;
355 KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE,
356 ("random_harvest_internal: origin %d invalid\n", origin));
358 /* Mask out unwanted sources */
359 if (!(harvest_source_mask & (1U << origin)))
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;
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);
379 entropyfifo.ring_in = ring_in;
381 mtx_unlock_spin(&harvest_mtx);