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*0a3a36cdSConrad Meyer #include <signal.h> 3859488f25SXin LI #include <stdbool.h> 39e9ac2743SConrad Meyer #include <stdlib.h> 40e9ac2743SConrad Meyer 41e9ac2743SConrad Meyer #include "libc_private.h" 42e9ac2743SConrad Meyer 4359488f25SXin LI /* First __FreeBSD_version bump after introduction of getrandom(2) (r331279) */ 4459488f25SXin LI #define GETRANDOM_FIRST 1200061 4559488f25SXin LI 46c1e80940SXin LI extern int __sysctl(int *, u_int, void *, size_t *, void *, size_t); 47c1e80940SXin LI 48*0a3a36cdSConrad Meyer static inline void 49*0a3a36cdSConrad Meyer _getentropy_fail(void) 50*0a3a36cdSConrad Meyer { 51*0a3a36cdSConrad Meyer raise(SIGKILL); 52*0a3a36cdSConrad Meyer } 53*0a3a36cdSConrad Meyer 54c1e80940SXin LI static size_t 55c1e80940SXin LI arnd_sysctl(u_char *buf, size_t size) 56c1e80940SXin LI { 57c1e80940SXin LI int mib[2]; 58c1e80940SXin LI size_t len, done; 59c1e80940SXin LI 60c1e80940SXin LI mib[0] = CTL_KERN; 61c1e80940SXin LI mib[1] = KERN_ARND; 62c1e80940SXin LI done = 0; 63c1e80940SXin LI 64c1e80940SXin LI do { 65c1e80940SXin LI len = size; 66c1e80940SXin LI if (__sysctl(mib, 2, buf, &len, NULL, 0) == -1) 67c1e80940SXin LI return (done); 68c1e80940SXin LI done += len; 69c1e80940SXin LI buf += len; 70c1e80940SXin LI size -= len; 71c1e80940SXin LI } while (size > 0); 72c1e80940SXin LI 73c1e80940SXin LI return (done); 74c1e80940SXin LI } 75c1e80940SXin LI 7608a7e74cSConrad Meyer /* 7708a7e74cSConrad Meyer * If a newer libc is accidentally installed on an older kernel, provide high 7808a7e74cSConrad Meyer * quality random data anyway. The sysctl interface is not as fast and does 7908a7e74cSConrad Meyer * not block by itself, but is provided by even very old kernels. 8008a7e74cSConrad Meyer */ 8108a7e74cSConrad Meyer static int 8208a7e74cSConrad Meyer getentropy_fallback(void *buf, size_t buflen) 8308a7e74cSConrad Meyer { 8408a7e74cSConrad Meyer /* 8508a7e74cSConrad Meyer * oldp (buf) == NULL has a special meaning for sysctl that results in 8608a7e74cSConrad Meyer * no EFAULT. For compatibility with the kernel getrandom(2), detect 8708a7e74cSConrad Meyer * this case and return the appropriate error. 8808a7e74cSConrad Meyer */ 8908a7e74cSConrad Meyer if (buf == NULL && buflen > 0) { 9008a7e74cSConrad Meyer errno = EFAULT; 9108a7e74cSConrad Meyer return (-1); 9208a7e74cSConrad Meyer } 93c1e80940SXin LI if (arnd_sysctl(buf, buflen) != buflen) { 9408a7e74cSConrad Meyer if (errno == EFAULT) 9508a7e74cSConrad Meyer return (-1); 9608a7e74cSConrad Meyer /* 97*0a3a36cdSConrad Meyer * This cannot happen. arnd_sysctl() spins until the random 9808a7e74cSConrad Meyer * device is seeded and then repeatedly reads until the full 9908a7e74cSConrad Meyer * request is satisfied. The only way for this to return a zero 10008a7e74cSConrad Meyer * byte or short read is if sysctl(2) on the kern.arandom MIB 101*0a3a36cdSConrad Meyer * fails. In this case, excepting the user-provided-a-bogus- 10208a7e74cSConrad Meyer * buffer EFAULT, give up (like for arc4random(3)'s arc4_stir). 10308a7e74cSConrad Meyer */ 104*0a3a36cdSConrad Meyer _getentropy_fail(); 10508a7e74cSConrad Meyer } 10608a7e74cSConrad Meyer return (0); 10708a7e74cSConrad Meyer } 10808a7e74cSConrad Meyer 109e9ac2743SConrad Meyer int 110e9ac2743SConrad Meyer getentropy(void *buf, size_t buflen) 111e9ac2743SConrad Meyer { 112e9ac2743SConrad Meyer ssize_t rd; 11359488f25SXin LI bool have_getrandom; 114e9ac2743SConrad Meyer 115e9ac2743SConrad Meyer if (buflen > 256) { 116e9ac2743SConrad Meyer errno = EIO; 117e9ac2743SConrad Meyer return (-1); 118e9ac2743SConrad Meyer } 119e9ac2743SConrad Meyer 12059488f25SXin LI have_getrandom = (__getosreldate() >= GETRANDOM_FIRST); 12159488f25SXin LI 122e9ac2743SConrad Meyer while (buflen > 0) { 12359488f25SXin LI if (have_getrandom) { 124e9ac2743SConrad Meyer rd = getrandom(buf, buflen, 0); 125e9ac2743SConrad Meyer if (rd == -1) { 12659488f25SXin LI switch (errno) { 12759488f25SXin LI case ECAPMODE: 12859488f25SXin LI /* 12959488f25SXin LI * Kernel >= r331280 and < r337999 13059488f25SXin LI * will return ECAPMODE when the 13159488f25SXin LI * caller is already in capability 13259488f25SXin LI * mode, fallback to traditional 13359488f25SXin LI * method in this case. 13459488f25SXin LI */ 13559488f25SXin LI have_getrandom = false; 136e9ac2743SConrad Meyer continue; 13759488f25SXin LI case EINTR: 13859488f25SXin LI continue; 139*0a3a36cdSConrad Meyer case EFAULT: 140e9ac2743SConrad Meyer return (-1); 141*0a3a36cdSConrad Meyer default: 142*0a3a36cdSConrad Meyer _getentropy_fail(); 143e9ac2743SConrad Meyer } 14459488f25SXin LI } 14559488f25SXin LI } else { 14659488f25SXin LI return (getentropy_fallback(buf, buflen)); 14759488f25SXin LI } 148e9ac2743SConrad Meyer 149e9ac2743SConrad Meyer /* This cannot happen. */ 150e9ac2743SConrad Meyer if (rd == 0) 151*0a3a36cdSConrad Meyer _getentropy_fail(); 152e9ac2743SConrad Meyer 153e9ac2743SConrad Meyer buf = (char *)buf + rd; 154e9ac2743SConrad Meyer buflen -= rd; 155e9ac2743SConrad Meyer } 156e9ac2743SConrad Meyer 157e9ac2743SConrad Meyer return (0); 158e9ac2743SConrad Meyer } 159