1 /*        $NetBSD: random.c,v 1.12 2024/08/27 00:56:47 riastradh Exp $          */
2 
3 /*-
4  * Copyright (c) 2019 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Taylor R. Campbell.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * /dev/random, /dev/urandom -- stateless version
34  *
35  *        For short reads from /dev/urandom, up to 256 bytes, read from a
36  *        per-CPU NIST Hash_DRBG instance that is reseeded as soon as the
37  *        system has enough entropy.
38  *
39  *        For all other reads, instantiate a fresh NIST Hash_DRBG from
40  *        the global entropy pool, and draw from it.
41  *
42  *        Each read is independent; there is no per-open state.
43  *        Concurrent reads from the same open run in parallel.
44  *
45  *        Reading from /dev/random may block until entropy is available.
46  *        Either device may return short reads if interrupted.
47  */
48 
49 #include <sys/cdefs.h>
50 __KERNEL_RCSID(0, "$NetBSD: random.c,v 1.12 2024/08/27 00:56:47 riastradh Exp $");
51 
52 #include <sys/param.h>
53 #include <sys/types.h>
54 #include <sys/atomic.h>
55 #include <sys/conf.h>
56 #include <sys/cprng.h>
57 #include <sys/entropy.h>
58 #include <sys/errno.h>
59 #include <sys/event.h>
60 #include <sys/fcntl.h>
61 #include <sys/kauth.h>
62 #include <sys/kmem.h>
63 #include <sys/lwp.h>
64 #include <sys/poll.h>
65 #include <sys/random.h>
66 #include <sys/rnd.h>
67 #include <sys/rndsource.h>
68 #include <sys/signalvar.h>
69 #include <sys/systm.h>
70 #include <sys/vnode.h>                  /* IO_NDELAY */
71 
72 #include "ioconf.h"
73 
74 static dev_type_open(random_open);
75 static dev_type_close(random_close);
76 static dev_type_ioctl(random_ioctl);
77 static dev_type_poll(random_poll);
78 static dev_type_kqfilter(random_kqfilter);
79 static dev_type_read(random_read);
80 static dev_type_write(random_write);
81 
82 const struct cdevsw rnd_cdevsw = {
83           .d_open = random_open,
84           .d_close = random_close,
85           .d_read = random_read,
86           .d_write = random_write,
87           .d_ioctl = random_ioctl,
88           .d_stop = nostop,
89           .d_tty = notty,
90           .d_poll = random_poll,
91           .d_mmap = nommap,
92           .d_kqfilter = random_kqfilter,
93           .d_discard = nodiscard,
94           .d_flag = D_OTHER|D_MPSAFE,
95 };
96 
97 #define   RANDOM_BUFSIZE      512       /* XXX pulled from arse */
98 
99 /* Entropy source for writes to /dev/random and /dev/urandom */
100 static krndsource_t user_rndsource;
101 
102 void
rndattach(int num)103 rndattach(int num)
104 {
105 
106           rnd_attach_source(&user_rndsource, "/dev/random", RND_TYPE_UNKNOWN,
107               RND_FLAG_COLLECT_VALUE);
108 }
109 
110 static int
random_open(dev_t dev,int flags,int fmt,struct lwp * l)111 random_open(dev_t dev, int flags, int fmt, struct lwp *l)
112 {
113 
114           /* Validate minor.  */
115           switch (minor(dev)) {
116           case RND_DEV_RANDOM:
117           case RND_DEV_URANDOM:
118                     break;
119           default:
120                     return ENXIO;
121           }
122 
123           return 0;
124 }
125 
126 static int
random_close(dev_t dev,int flags,int fmt,struct lwp * l)127 random_close(dev_t dev, int flags, int fmt, struct lwp *l)
128 {
129 
130           /* Success!  */
131           return 0;
132 }
133 
134 static int
random_ioctl(dev_t dev,unsigned long cmd,void * data,int flag,struct lwp * l)135 random_ioctl(dev_t dev, unsigned long cmd, void *data, int flag, struct lwp *l)
136 {
137 
138           /*
139            * No non-blocking/async options; otherwise defer to
140            * entropy_ioctl.
141            */
142           switch (cmd) {
143           case FIONBIO:
144           case FIOASYNC:
145                     return 0;
146           default:
147                     return entropy_ioctl(cmd, data);
148           }
149 }
150 
151 static int
random_poll(dev_t dev,int events,struct lwp * l)152 random_poll(dev_t dev, int events, struct lwp *l)
153 {
154 
155           /* /dev/random may block; /dev/urandom is always ready.  */
156           switch (minor(dev)) {
157           case RND_DEV_RANDOM:
158                     return entropy_poll(events);
159           case RND_DEV_URANDOM:
160                     return events & (POLLIN|POLLRDNORM | POLLOUT|POLLWRNORM);
161           default:
162                     return 0;
163           }
164 }
165 
166 static int
random_kqfilter(dev_t dev,struct knote * kn)167 random_kqfilter(dev_t dev, struct knote *kn)
168 {
169 
170           /* Validate the event filter.  */
171           switch (kn->kn_filter) {
172           case EVFILT_READ:
173           case EVFILT_WRITE:
174                     break;
175           default:
176                     return EINVAL;
177           }
178 
179           /* /dev/random may block; /dev/urandom never does.  */
180           switch (minor(dev)) {
181           case RND_DEV_RANDOM:
182                     if (kn->kn_filter == EVFILT_READ)
183                               return entropy_kqfilter(kn);
184                     /* FALLTHROUGH */
185           case RND_DEV_URANDOM:
186                     kn->kn_fop = &seltrue_filtops;
187                     return 0;
188           default:
189                     return ENXIO;
190           }
191 }
192 
193 /*
194  * random_read(dev, uio, flags)
195  *
196  *        Generate data from a PRNG seeded from the entropy pool.
197  *
198  *        - If /dev/random, block until we have full entropy, or fail
199  *          with EWOULDBLOCK, and if `depleting' entropy, return at most
200  *          the entropy pool's capacity at once.
201  *
202  *        - If /dev/urandom, generate data from whatever is in the
203  *          entropy pool now.
204  *
205  *        On interrupt, return a short read, but not shorter than 256
206  *        bytes (actually, no shorter than RANDOM_BUFSIZE bytes, which is
207  *        512 for hysterical raisins).
208  */
209 static int
random_read(dev_t dev,struct uio * uio,int flags)210 random_read(dev_t dev, struct uio *uio, int flags)
211 {
212           int gflags;
213 
214           /* Set the appropriate GRND_* mode.  */
215           switch (minor(dev)) {
216           case RND_DEV_RANDOM:
217                     gflags = GRND_RANDOM;
218                     break;
219           case RND_DEV_URANDOM:
220                     gflags = GRND_INSECURE;
221                     break;
222           default:
223                     return ENXIO;
224           }
225 
226           /*
227            * Set GRND_NONBLOCK if the user requested IO_NDELAY (i.e., the
228            * file was opened with O_NONBLOCK).
229            */
230           if (flags & IO_NDELAY)
231                     gflags |= GRND_NONBLOCK;
232 
233           /* Defer to getrandom.  */
234           return dogetrandom(uio, gflags);
235 }
236 
237 /*
238  * random_write(dev, uio, flags)
239  *
240  *        Enter data from uio into the entropy pool.
241  *
242  *        Assume privileged users provide full entropy, and unprivileged
243  *        users provide no entropy.  If you have a nonuniform source of
244  *        data with n bytes of min-entropy, hash it with an XOF like
245  *        SHAKE128 into exactly n bytes first.
246  */
247 static int
random_write(dev_t dev,struct uio * uio,int flags)248 random_write(dev_t dev, struct uio *uio, int flags)
249 {
250           kauth_cred_t cred = kauth_cred_get();
251           uint8_t *buf;
252           bool privileged = false, any = false;
253           int error = 0;
254 
255           /* Verify user's authorization to affect the entropy pool.  */
256           error = kauth_authorize_device(cred, KAUTH_DEVICE_RND_ADDDATA,
257               NULL, NULL, NULL, NULL);
258           if (error)
259                     return error;
260 
261           /*
262            * Check whether user is privileged.  If so, assume user
263            * furnishes full-entropy data; if not, accept user's data but
264            * assume it has zero entropy when we do accounting.  If you
265            * want to specify less entropy, use ioctl(RNDADDDATA).
266            */
267           if (kauth_authorize_device(cred, KAUTH_DEVICE_RND_ADDDATA_ESTIMATE,
268                     NULL, NULL, NULL, NULL) == 0)
269                     privileged = true;
270 
271           /* Get a buffer for transfers.  */
272           buf = kmem_alloc(RANDOM_BUFSIZE, KM_SLEEP);
273 
274           /* Consume data.  */
275           while (uio->uio_resid) {
276                     size_t n = MIN(uio->uio_resid, RANDOM_BUFSIZE);
277 
278                     /* Transfer n bytes in and enter them into the pool.  */
279                     error = uiomove(buf, n, uio);
280                     if (error)
281                               break;
282                     rnd_add_data(&user_rndsource, buf, n, privileged ? n*NBBY : 0);
283                     any = true;
284 
285                     /* Now's a good time to yield if needed.  */
286                     preempt_point();
287 
288                     /* Check for interruption.  */
289                     if (__predict_false(curlwp->l_flag & LW_PENDSIG) &&
290                         sigispending(curlwp, 0)) {
291                               error = EINTR;
292                               break;
293                     }
294           }
295 
296           /* Zero the buffer and free it.  */
297           explicit_memset(buf, 0, RANDOM_BUFSIZE);
298           kmem_free(buf, RANDOM_BUFSIZE);
299 
300           /* If we added anything, consolidate entropy now.  */
301           if (any && error == 0)
302                     error = entropy_consolidate();
303 
304           return error;
305 }
306