]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/random/random_harvestq.c
Merge ACPICA 20150515.
[FreeBSD/FreeBSD.git] / sys / dev / random / random_harvestq.c
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 }