1e9ac2743SConrad Meyer /*- 2e9ac2743SConrad Meyer * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3e9ac2743SConrad Meyer * 4e9ac2743SConrad Meyer * Copyright (c) 2018 Conrad Meyer <cem@FreeBSD.org> 5e9ac2743SConrad Meyer * All rights reserved. 6e9ac2743SConrad Meyer * 7e9ac2743SConrad Meyer * Redistribution and use in source and binary forms, with or without 8e9ac2743SConrad Meyer * modification, are permitted provided that the following conditions 9e9ac2743SConrad Meyer * are met: 10e9ac2743SConrad Meyer * 1. Redistributions of source code must retain the above copyright 11e9ac2743SConrad Meyer * notice, this list of conditions and the following disclaimer. 12e9ac2743SConrad Meyer * 2. Redistributions in binary form must reproduce the above copyright 13e9ac2743SConrad Meyer * notice, this list of conditions and the following disclaimer in the 14e9ac2743SConrad Meyer * documentation and/or other materials provided with the distribution. 15e9ac2743SConrad Meyer * 16e9ac2743SConrad Meyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17e9ac2743SConrad Meyer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18e9ac2743SConrad Meyer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19e9ac2743SConrad Meyer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20e9ac2743SConrad Meyer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21e9ac2743SConrad Meyer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22e9ac2743SConrad Meyer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23e9ac2743SConrad Meyer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24e9ac2743SConrad Meyer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25e9ac2743SConrad Meyer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26e9ac2743SConrad Meyer * SUCH DAMAGE. 27e9ac2743SConrad Meyer */ 28e9ac2743SConrad Meyer 29e9ac2743SConrad Meyer #include <sys/cdefs.h> 30e9ac2743SConrad Meyer __FBSDID("$FreeBSD$"); 31e9ac2743SConrad Meyer 32e9ac2743SConrad Meyer #include <sys/param.h> 33e9ac2743SConrad Meyer #include <sys/random.h> 34c1e80940SXin LI #include <sys/sysctl.h> 35e9ac2743SConrad Meyer 36e9ac2743SConrad Meyer #include <errno.h> 37*59488f25SXin LI #include <stdbool.h> 38e9ac2743SConrad Meyer #include <stdlib.h> 39e9ac2743SConrad Meyer 40e9ac2743SConrad Meyer #include "libc_private.h" 41e9ac2743SConrad Meyer 42*59488f25SXin LI /* First __FreeBSD_version bump after introduction of getrandom(2) (r331279) */ 43*59488f25SXin LI #define GETRANDOM_FIRST 1200061 44*59488f25SXin LI 45c1e80940SXin LI extern int __sysctl(int *, u_int, void *, size_t *, void *, size_t); 46c1e80940SXin LI 47c1e80940SXin LI static size_t 48c1e80940SXin LI arnd_sysctl(u_char *buf, size_t size) 49c1e80940SXin LI { 50c1e80940SXin LI int mib[2]; 51c1e80940SXin LI size_t len, done; 52c1e80940SXin LI 53c1e80940SXin LI mib[0] = CTL_KERN; 54c1e80940SXin LI mib[1] = KERN_ARND; 55c1e80940SXin LI done = 0; 56c1e80940SXin LI 57c1e80940SXin LI do { 58c1e80940SXin LI len = size; 59c1e80940SXin LI if (__sysctl(mib, 2, buf, &len, NULL, 0) == -1) 60c1e80940SXin LI return (done); 61c1e80940SXin LI done += len; 62c1e80940SXin LI buf += len; 63c1e80940SXin LI size -= len; 64c1e80940SXin LI } while (size > 0); 65c1e80940SXin LI 66c1e80940SXin LI return (done); 67c1e80940SXin LI } 68c1e80940SXin LI 6908a7e74cSConrad Meyer /* 7008a7e74cSConrad Meyer * If a newer libc is accidentally installed on an older kernel, provide high 7108a7e74cSConrad Meyer * quality random data anyway. The sysctl interface is not as fast and does 7208a7e74cSConrad Meyer * not block by itself, but is provided by even very old kernels. 7308a7e74cSConrad Meyer */ 7408a7e74cSConrad Meyer static int 7508a7e74cSConrad Meyer getentropy_fallback(void *buf, size_t buflen) 7608a7e74cSConrad Meyer { 7708a7e74cSConrad Meyer /* 7808a7e74cSConrad Meyer * oldp (buf) == NULL has a special meaning for sysctl that results in 7908a7e74cSConrad Meyer * no EFAULT. For compatibility with the kernel getrandom(2), detect 8008a7e74cSConrad Meyer * this case and return the appropriate error. 8108a7e74cSConrad Meyer */ 8208a7e74cSConrad Meyer if (buf == NULL && buflen > 0) { 8308a7e74cSConrad Meyer errno = EFAULT; 8408a7e74cSConrad Meyer return (-1); 8508a7e74cSConrad Meyer } 86c1e80940SXin LI if (arnd_sysctl(buf, buflen) != buflen) { 8708a7e74cSConrad Meyer if (errno == EFAULT) 8808a7e74cSConrad Meyer return (-1); 8908a7e74cSConrad Meyer /* 9008a7e74cSConrad Meyer * This cannot happen. _arc4_sysctl() spins until the random 9108a7e74cSConrad Meyer * device is seeded and then repeatedly reads until the full 9208a7e74cSConrad Meyer * request is satisfied. The only way for this to return a zero 9308a7e74cSConrad Meyer * byte or short read is if sysctl(2) on the kern.arandom MIB 9408a7e74cSConrad Meyer * fails. In this case, exceping the user-provided-a-bogus- 9508a7e74cSConrad Meyer * buffer EFAULT, give up (like for arc4random(3)'s arc4_stir). 9608a7e74cSConrad Meyer */ 9708a7e74cSConrad Meyer abort(); 9808a7e74cSConrad Meyer } 9908a7e74cSConrad Meyer return (0); 10008a7e74cSConrad Meyer } 10108a7e74cSConrad Meyer 102e9ac2743SConrad Meyer int 103e9ac2743SConrad Meyer getentropy(void *buf, size_t buflen) 104e9ac2743SConrad Meyer { 105e9ac2743SConrad Meyer ssize_t rd; 106*59488f25SXin LI bool have_getrandom; 107e9ac2743SConrad Meyer 108e9ac2743SConrad Meyer if (buflen > 256) { 109e9ac2743SConrad Meyer errno = EIO; 110e9ac2743SConrad Meyer return (-1); 111e9ac2743SConrad Meyer } 112e9ac2743SConrad Meyer 113*59488f25SXin LI have_getrandom = (__getosreldate() >= GETRANDOM_FIRST); 114*59488f25SXin LI 115e9ac2743SConrad Meyer while (buflen > 0) { 116*59488f25SXin LI if (have_getrandom) { 117e9ac2743SConrad Meyer rd = getrandom(buf, buflen, 0); 118e9ac2743SConrad Meyer if (rd == -1) { 119*59488f25SXin LI switch (errno) { 120*59488f25SXin LI case ECAPMODE: 121*59488f25SXin LI /* 122*59488f25SXin LI * Kernel >= r331280 and < r337999 123*59488f25SXin LI * will return ECAPMODE when the 124*59488f25SXin LI * caller is already in capability 125*59488f25SXin LI * mode, fallback to traditional 126*59488f25SXin LI * method in this case. 127*59488f25SXin LI */ 128*59488f25SXin LI have_getrandom = false; 129e9ac2743SConrad Meyer continue; 130*59488f25SXin LI case EINTR: 131*59488f25SXin LI continue; 132*59488f25SXin LI default: 133e9ac2743SConrad Meyer return (-1); 134e9ac2743SConrad Meyer } 135*59488f25SXin LI } 136*59488f25SXin LI } else { 137*59488f25SXin LI return (getentropy_fallback(buf, buflen)); 138*59488f25SXin LI } 139e9ac2743SConrad Meyer 140e9ac2743SConrad Meyer /* This cannot happen. */ 141e9ac2743SConrad Meyer if (rd == 0) 142e9ac2743SConrad Meyer abort(); 143e9ac2743SConrad Meyer 144e9ac2743SConrad Meyer buf = (char *)buf + rd; 145e9ac2743SConrad Meyer buflen -= rd; 146e9ac2743SConrad Meyer } 147e9ac2743SConrad Meyer 148e9ac2743SConrad Meyer return (0); 149e9ac2743SConrad Meyer } 150