1*4dd1804bSriastradh /* $NetBSD: random.c,v 1.12 2024/08/27 00:56:47 riastradh Exp $ */ 25084c1b5Sriastradh 35084c1b5Sriastradh /*- 45084c1b5Sriastradh * Copyright (c) 2019 The NetBSD Foundation, Inc. 55084c1b5Sriastradh * All rights reserved. 65084c1b5Sriastradh * 75084c1b5Sriastradh * This code is derived from software contributed to The NetBSD Foundation 85084c1b5Sriastradh * by Taylor R. Campbell. 95084c1b5Sriastradh * 105084c1b5Sriastradh * Redistribution and use in source and binary forms, with or without 115084c1b5Sriastradh * modification, are permitted provided that the following conditions 125084c1b5Sriastradh * are met: 135084c1b5Sriastradh * 1. Redistributions of source code must retain the above copyright 145084c1b5Sriastradh * notice, this list of conditions and the following disclaimer. 155084c1b5Sriastradh * 2. Redistributions in binary form must reproduce the above copyright 165084c1b5Sriastradh * notice, this list of conditions and the following disclaimer in the 175084c1b5Sriastradh * documentation and/or other materials provided with the distribution. 185084c1b5Sriastradh * 195084c1b5Sriastradh * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 205084c1b5Sriastradh * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 215084c1b5Sriastradh * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 225084c1b5Sriastradh * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 235084c1b5Sriastradh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 245084c1b5Sriastradh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 255084c1b5Sriastradh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 265084c1b5Sriastradh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 275084c1b5Sriastradh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 285084c1b5Sriastradh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 295084c1b5Sriastradh * POSSIBILITY OF SUCH DAMAGE. 305084c1b5Sriastradh */ 315084c1b5Sriastradh 325084c1b5Sriastradh /* 335084c1b5Sriastradh * /dev/random, /dev/urandom -- stateless version 345084c1b5Sriastradh * 355084c1b5Sriastradh * For short reads from /dev/urandom, up to 256 bytes, read from a 365084c1b5Sriastradh * per-CPU NIST Hash_DRBG instance that is reseeded as soon as the 375084c1b5Sriastradh * system has enough entropy. 385084c1b5Sriastradh * 395084c1b5Sriastradh * For all other reads, instantiate a fresh NIST Hash_DRBG from 405084c1b5Sriastradh * the global entropy pool, and draw from it. 415084c1b5Sriastradh * 425084c1b5Sriastradh * Each read is independent; there is no per-open state. 435084c1b5Sriastradh * Concurrent reads from the same open run in parallel. 445084c1b5Sriastradh * 455084c1b5Sriastradh * Reading from /dev/random may block until entropy is available. 465084c1b5Sriastradh * Either device may return short reads if interrupted. 475084c1b5Sriastradh */ 485084c1b5Sriastradh 495084c1b5Sriastradh #include <sys/cdefs.h> 50*4dd1804bSriastradh __KERNEL_RCSID(0, "$NetBSD: random.c,v 1.12 2024/08/27 00:56:47 riastradh Exp $"); 515084c1b5Sriastradh 525084c1b5Sriastradh #include <sys/param.h> 535084c1b5Sriastradh #include <sys/types.h> 54ea26d8a7Sriastradh #include <sys/atomic.h> 555084c1b5Sriastradh #include <sys/conf.h> 565084c1b5Sriastradh #include <sys/cprng.h> 575084c1b5Sriastradh #include <sys/entropy.h> 585084c1b5Sriastradh #include <sys/errno.h> 595084c1b5Sriastradh #include <sys/event.h> 605084c1b5Sriastradh #include <sys/fcntl.h> 615084c1b5Sriastradh #include <sys/kauth.h> 621b74d9d4Sriastradh #include <sys/kmem.h> 635084c1b5Sriastradh #include <sys/lwp.h> 645084c1b5Sriastradh #include <sys/poll.h> 65bdad8b27Sriastradh #include <sys/random.h> 665084c1b5Sriastradh #include <sys/rnd.h> 675084c1b5Sriastradh #include <sys/rndsource.h> 685084c1b5Sriastradh #include <sys/signalvar.h> 695084c1b5Sriastradh #include <sys/systm.h> 70909ca466Sriastradh #include <sys/vnode.h> /* IO_NDELAY */ 715084c1b5Sriastradh 725084c1b5Sriastradh #include "ioconf.h" 735084c1b5Sriastradh 745084c1b5Sriastradh static dev_type_open(random_open); 755084c1b5Sriastradh static dev_type_close(random_close); 765084c1b5Sriastradh static dev_type_ioctl(random_ioctl); 775084c1b5Sriastradh static dev_type_poll(random_poll); 785084c1b5Sriastradh static dev_type_kqfilter(random_kqfilter); 795084c1b5Sriastradh static dev_type_read(random_read); 805084c1b5Sriastradh static dev_type_write(random_write); 815084c1b5Sriastradh 825084c1b5Sriastradh const struct cdevsw rnd_cdevsw = { 835084c1b5Sriastradh .d_open = random_open, 845084c1b5Sriastradh .d_close = random_close, 855084c1b5Sriastradh .d_read = random_read, 865084c1b5Sriastradh .d_write = random_write, 875084c1b5Sriastradh .d_ioctl = random_ioctl, 885084c1b5Sriastradh .d_stop = nostop, 895084c1b5Sriastradh .d_tty = notty, 905084c1b5Sriastradh .d_poll = random_poll, 915084c1b5Sriastradh .d_mmap = nommap, 925084c1b5Sriastradh .d_kqfilter = random_kqfilter, 935084c1b5Sriastradh .d_discard = nodiscard, 945084c1b5Sriastradh .d_flag = D_OTHER|D_MPSAFE, 955084c1b5Sriastradh }; 965084c1b5Sriastradh 975084c1b5Sriastradh #define RANDOM_BUFSIZE 512 /* XXX pulled from arse */ 985084c1b5Sriastradh 995084c1b5Sriastradh /* Entropy source for writes to /dev/random and /dev/urandom */ 1005084c1b5Sriastradh static krndsource_t user_rndsource; 1015084c1b5Sriastradh 1025084c1b5Sriastradh void 1035084c1b5Sriastradh rndattach(int num) 1045084c1b5Sriastradh { 1055084c1b5Sriastradh 1065084c1b5Sriastradh rnd_attach_source(&user_rndsource, "/dev/random", RND_TYPE_UNKNOWN, 1075084c1b5Sriastradh RND_FLAG_COLLECT_VALUE); 1085084c1b5Sriastradh } 1095084c1b5Sriastradh 1105084c1b5Sriastradh static int 1115084c1b5Sriastradh random_open(dev_t dev, int flags, int fmt, struct lwp *l) 1125084c1b5Sriastradh { 1135084c1b5Sriastradh 1145084c1b5Sriastradh /* Validate minor. */ 1155084c1b5Sriastradh switch (minor(dev)) { 1165084c1b5Sriastradh case RND_DEV_RANDOM: 1175084c1b5Sriastradh case RND_DEV_URANDOM: 1185084c1b5Sriastradh break; 1195084c1b5Sriastradh default: 1205084c1b5Sriastradh return ENXIO; 1215084c1b5Sriastradh } 1225084c1b5Sriastradh 1235084c1b5Sriastradh return 0; 1245084c1b5Sriastradh } 1255084c1b5Sriastradh 1265084c1b5Sriastradh static int 1275084c1b5Sriastradh random_close(dev_t dev, int flags, int fmt, struct lwp *l) 1285084c1b5Sriastradh { 1295084c1b5Sriastradh 1305084c1b5Sriastradh /* Success! */ 1315084c1b5Sriastradh return 0; 1325084c1b5Sriastradh } 1335084c1b5Sriastradh 1345084c1b5Sriastradh static int 1355084c1b5Sriastradh random_ioctl(dev_t dev, unsigned long cmd, void *data, int flag, struct lwp *l) 1365084c1b5Sriastradh { 1375084c1b5Sriastradh 1385084c1b5Sriastradh /* 1395084c1b5Sriastradh * No non-blocking/async options; otherwise defer to 1405084c1b5Sriastradh * entropy_ioctl. 1415084c1b5Sriastradh */ 1425084c1b5Sriastradh switch (cmd) { 1435084c1b5Sriastradh case FIONBIO: 1445084c1b5Sriastradh case FIOASYNC: 1455084c1b5Sriastradh return 0; 1465084c1b5Sriastradh default: 1475084c1b5Sriastradh return entropy_ioctl(cmd, data); 1485084c1b5Sriastradh } 1495084c1b5Sriastradh } 1505084c1b5Sriastradh 1515084c1b5Sriastradh static int 1525084c1b5Sriastradh random_poll(dev_t dev, int events, struct lwp *l) 1535084c1b5Sriastradh { 1545084c1b5Sriastradh 1555084c1b5Sriastradh /* /dev/random may block; /dev/urandom is always ready. */ 1565084c1b5Sriastradh switch (minor(dev)) { 1575084c1b5Sriastradh case RND_DEV_RANDOM: 1585084c1b5Sriastradh return entropy_poll(events); 1595084c1b5Sriastradh case RND_DEV_URANDOM: 1605084c1b5Sriastradh return events & (POLLIN|POLLRDNORM | POLLOUT|POLLWRNORM); 1615084c1b5Sriastradh default: 1625084c1b5Sriastradh return 0; 1635084c1b5Sriastradh } 1645084c1b5Sriastradh } 1655084c1b5Sriastradh 1665084c1b5Sriastradh static int 1675084c1b5Sriastradh random_kqfilter(dev_t dev, struct knote *kn) 1685084c1b5Sriastradh { 1695084c1b5Sriastradh 1705084c1b5Sriastradh /* Validate the event filter. */ 1715084c1b5Sriastradh switch (kn->kn_filter) { 1725084c1b5Sriastradh case EVFILT_READ: 1735084c1b5Sriastradh case EVFILT_WRITE: 1745084c1b5Sriastradh break; 1755084c1b5Sriastradh default: 1765084c1b5Sriastradh return EINVAL; 1775084c1b5Sriastradh } 1785084c1b5Sriastradh 1795084c1b5Sriastradh /* /dev/random may block; /dev/urandom never does. */ 1805084c1b5Sriastradh switch (minor(dev)) { 1815084c1b5Sriastradh case RND_DEV_RANDOM: 1825084c1b5Sriastradh if (kn->kn_filter == EVFILT_READ) 1835084c1b5Sriastradh return entropy_kqfilter(kn); 1845084c1b5Sriastradh /* FALLTHROUGH */ 1855084c1b5Sriastradh case RND_DEV_URANDOM: 1865084c1b5Sriastradh kn->kn_fop = &seltrue_filtops; 1875084c1b5Sriastradh return 0; 1885084c1b5Sriastradh default: 1895084c1b5Sriastradh return ENXIO; 1905084c1b5Sriastradh } 1915084c1b5Sriastradh } 1925084c1b5Sriastradh 1935084c1b5Sriastradh /* 1945084c1b5Sriastradh * random_read(dev, uio, flags) 1955084c1b5Sriastradh * 1965084c1b5Sriastradh * Generate data from a PRNG seeded from the entropy pool. 1975084c1b5Sriastradh * 1985084c1b5Sriastradh * - If /dev/random, block until we have full entropy, or fail 1995084c1b5Sriastradh * with EWOULDBLOCK, and if `depleting' entropy, return at most 2005084c1b5Sriastradh * the entropy pool's capacity at once. 2015084c1b5Sriastradh * 2025084c1b5Sriastradh * - If /dev/urandom, generate data from whatever is in the 2035084c1b5Sriastradh * entropy pool now. 2045084c1b5Sriastradh * 2055084c1b5Sriastradh * On interrupt, return a short read, but not shorter than 256 2065084c1b5Sriastradh * bytes (actually, no shorter than RANDOM_BUFSIZE bytes, which is 2075084c1b5Sriastradh * 512 for hysterical raisins). 2085084c1b5Sriastradh */ 2095084c1b5Sriastradh static int 2105084c1b5Sriastradh random_read(dev_t dev, struct uio *uio, int flags) 2115084c1b5Sriastradh { 212bdad8b27Sriastradh int gflags; 2135084c1b5Sriastradh 214bdad8b27Sriastradh /* Set the appropriate GRND_* mode. */ 215bdad8b27Sriastradh switch (minor(dev)) { 216bdad8b27Sriastradh case RND_DEV_RANDOM: 217bdad8b27Sriastradh gflags = GRND_RANDOM; 2185084c1b5Sriastradh break; 219bdad8b27Sriastradh case RND_DEV_URANDOM: 220bdad8b27Sriastradh gflags = GRND_INSECURE; 2215084c1b5Sriastradh break; 222bdad8b27Sriastradh default: 223bdad8b27Sriastradh return ENXIO; 2245084c1b5Sriastradh } 2255084c1b5Sriastradh 226909ca466Sriastradh /* 227909ca466Sriastradh * Set GRND_NONBLOCK if the user requested IO_NDELAY (i.e., the 228909ca466Sriastradh * file was opened with O_NONBLOCK). 229909ca466Sriastradh */ 230909ca466Sriastradh if (flags & IO_NDELAY) 231bdad8b27Sriastradh gflags |= GRND_NONBLOCK; 2327460c1deSriastradh 233bdad8b27Sriastradh /* Defer to getrandom. */ 234bdad8b27Sriastradh return dogetrandom(uio, gflags); 2355084c1b5Sriastradh } 2365084c1b5Sriastradh 2375084c1b5Sriastradh /* 2385084c1b5Sriastradh * random_write(dev, uio, flags) 2395084c1b5Sriastradh * 2405084c1b5Sriastradh * Enter data from uio into the entropy pool. 2415084c1b5Sriastradh * 2425084c1b5Sriastradh * Assume privileged users provide full entropy, and unprivileged 2435084c1b5Sriastradh * users provide no entropy. If you have a nonuniform source of 2445084c1b5Sriastradh * data with n bytes of min-entropy, hash it with an XOF like 2455084c1b5Sriastradh * SHAKE128 into exactly n bytes first. 2465084c1b5Sriastradh */ 2475084c1b5Sriastradh static int 2485084c1b5Sriastradh random_write(dev_t dev, struct uio *uio, int flags) 2495084c1b5Sriastradh { 2505084c1b5Sriastradh kauth_cred_t cred = kauth_cred_get(); 2515084c1b5Sriastradh uint8_t *buf; 252bbed1747Sriastradh bool privileged = false, any = false; 2535084c1b5Sriastradh int error = 0; 2545084c1b5Sriastradh 2555084c1b5Sriastradh /* Verify user's authorization to affect the entropy pool. */ 2565084c1b5Sriastradh error = kauth_authorize_device(cred, KAUTH_DEVICE_RND_ADDDATA, 2575084c1b5Sriastradh NULL, NULL, NULL, NULL); 2585084c1b5Sriastradh if (error) 2595084c1b5Sriastradh return error; 2605084c1b5Sriastradh 2615084c1b5Sriastradh /* 2625084c1b5Sriastradh * Check whether user is privileged. If so, assume user 2635084c1b5Sriastradh * furnishes full-entropy data; if not, accept user's data but 2645084c1b5Sriastradh * assume it has zero entropy when we do accounting. If you 2655084c1b5Sriastradh * want to specify less entropy, use ioctl(RNDADDDATA). 2665084c1b5Sriastradh */ 2675084c1b5Sriastradh if (kauth_authorize_device(cred, KAUTH_DEVICE_RND_ADDDATA_ESTIMATE, 2685084c1b5Sriastradh NULL, NULL, NULL, NULL) == 0) 2695084c1b5Sriastradh privileged = true; 2705084c1b5Sriastradh 2715084c1b5Sriastradh /* Get a buffer for transfers. */ 2721b74d9d4Sriastradh buf = kmem_alloc(RANDOM_BUFSIZE, KM_SLEEP); 2735084c1b5Sriastradh 2745084c1b5Sriastradh /* Consume data. */ 2755084c1b5Sriastradh while (uio->uio_resid) { 2767460c1deSriastradh size_t n = MIN(uio->uio_resid, RANDOM_BUFSIZE); 2775084c1b5Sriastradh 2787460c1deSriastradh /* Transfer n bytes in and enter them into the pool. */ 2797460c1deSriastradh error = uiomove(buf, n, uio); 2807460c1deSriastradh if (error) 2817460c1deSriastradh break; 2827460c1deSriastradh rnd_add_data(&user_rndsource, buf, n, privileged ? n*NBBY : 0); 2837460c1deSriastradh any = true; 2845084c1b5Sriastradh 28564191176Sriastradh /* Now's a good time to yield if needed. */ 28664191176Sriastradh preempt_point(); 2875084c1b5Sriastradh 2885084c1b5Sriastradh /* Check for interruption. */ 2895084c1b5Sriastradh if (__predict_false(curlwp->l_flag & LW_PENDSIG) && 2905084c1b5Sriastradh sigispending(curlwp, 0)) { 2915729ed03Sriastradh error = EINTR; 2925084c1b5Sriastradh break; 2935084c1b5Sriastradh } 2945084c1b5Sriastradh } 2955084c1b5Sriastradh 2961b74d9d4Sriastradh /* Zero the buffer and free it. */ 2975084c1b5Sriastradh explicit_memset(buf, 0, RANDOM_BUFSIZE); 2981b74d9d4Sriastradh kmem_free(buf, RANDOM_BUFSIZE); 299bbed1747Sriastradh 300bbed1747Sriastradh /* If we added anything, consolidate entropy now. */ 301fd332dc4Sriastradh if (any && error == 0) 302*4dd1804bSriastradh error = entropy_consolidate(); 303bbed1747Sriastradh 3045084c1b5Sriastradh return error; 3055084c1b5Sriastradh } 306