/* $OpenBSD: arc4random.h,v 1.4 2015/01/15 06:57:18 deraadt Exp $ */12/*3* Copyright (c) 1996, David Mazieres <[email protected]>4* Copyright (c) 2008, Damien Miller <[email protected]>5* Copyright (c) 2013, Markus Friedl <[email protected]>6* Copyright (c) 2014, Theo de Raadt <[email protected]>7*8* Permission to use, copy, modify, and distribute this software for any9* purpose with or without fee is hereby granted, provided that the above10* copyright notice and this permission notice appear in all copies.11*12* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES13* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF14* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR15* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES16* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN17* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF18* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.19*/2021/*22* Stub functions for portability.23*/24#include <sys/elf.h>25#include <sys/endian.h>26#include <sys/mman.h>27#if ARC4RANDOM_FXRNG != 028#include <sys/time.h> /* for sys/vdso.h only. */29#include <sys/vdso.h>30#include <machine/atomic.h>31#endif3233#include <err.h>34#include <errno.h>35#include <signal.h>36#include <stdbool.h>37#include <stdint.h>3839#if ARC4RANDOM_FXRNG != 040/*41* The kernel root seed version is a 64-bit counter, but we truncate it to a42* 32-bit value in userspace for the convenience of 32-bit platforms. 32-bit43* rollover is not possible with the current reseed interval (1 hour at limit)44* without dynamic addition of new random devices (which also force a reseed in45* the FXRNG design). We don't have any dynamic device mechanism at this46* time, and anyway something else is very wrong if billions of new devices are47* being added.48*49* As is, it takes roughly 456,000 years of runtime to overflow the 32-bit50* version.51*/52#define fxrng_load_acq_generation(x) atomic_load_acq_32(x)53static struct vdso_fxrng_generation_1 *vdso_fxrngp;54#endif5556static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;57#define _ARC4_LOCK() \58do { \59if (__isthreaded) \60_pthread_mutex_lock(&arc4random_mtx); \61} while (0)6263#define _ARC4_UNLOCK() \64do { \65if (__isthreaded) \66_pthread_mutex_unlock(&arc4random_mtx); \67} while (0)6869static inline void70_getentropy_fail(void)71{72raise(SIGKILL);73}7475static inline void76_rs_initialize_fxrng(void)77{78#if ARC4RANDOM_FXRNG != 079struct vdso_fxrng_generation_1 *fxrngp;80int error;8182error = _elf_aux_info(AT_FXRNG, &fxrngp, sizeof(fxrngp));83if (error != 0) {84/*85* New userspace on an old or !RANDOM_FENESTRASX kernel; or an86* arch that does not have a VDSO page.87*/88return;89}9091/* Old userspace on newer kernel. */92if (fxrngp->fx_vdso_version != VDSO_FXRNG_VER_1)93return;9495vdso_fxrngp = fxrngp;96#endif97}9899static inline int100_rs_allocate(struct _rs **rsp, struct _rsx **rsxp)101{102struct {103struct _rs rs;104struct _rsx rsx;105} *p;106107if ((p = mmap(NULL, sizeof(*p), PROT_READ|PROT_WRITE,108MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)109return (-1);110/* Allow bootstrapping arc4random.c on Linux/macOS */111#ifdef INHERIT_ZERO112if (minherit(p, sizeof(*p), INHERIT_ZERO) == -1) {113munmap(p, sizeof(*p));114return (-1);115}116#endif117118_rs_initialize_fxrng();119120*rsp = &p->rs;121*rsxp = &p->rsx;122return (0);123}124125/*126* This isn't only detecting fork. We're also using the existing callback from127* _rs_stir_if_needed() to force arc4random(3) to reseed if the fenestrasX root128* seed version has changed. (That is, the root random(4) has reseeded from129* pooled entropy.)130*/131static inline void132_rs_forkdetect(void)133{134/* Detect fork (minherit(2) INHERIT_ZERO). */135if (__predict_false(rs == NULL || rsx == NULL))136return;137#if ARC4RANDOM_FXRNG != 0138/* If present, detect kernel FenestrasX seed version change. */139if (vdso_fxrngp == NULL)140return;141if (__predict_true(rsx->rs_seed_generation ==142fxrng_load_acq_generation(&vdso_fxrngp->fx_generation32)))143return;144#endif145/* Invalidate rs_buf to force "stir" (reseed). */146memset(rs, 0, sizeof(*rs));147}148149150