1/* $OpenBSD: arc4random.h,v 1.4 2015/01/15 06:57:18 deraadt Exp $ */ 2 3/* 4 * Copyright (c) 1996, David Mazieres <dm@uun.org> 5 * Copyright (c) 2008, Damien Miller <djm@openbsd.org> 6 * Copyright (c) 2013, Markus Friedl <markus@openbsd.org> 7 * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 * 21 * $FreeBSD$ 22 */ 23 24/* 25 * Stub functions for portability. 26 */ 27#include <sys/elf.h> 28#include <sys/endian.h> 29#include <sys/mman.h> 30#if ARC4RANDOM_FXRNG != 0 31#include <sys/time.h> /* for sys/vdso.h only. */ 32#include <sys/vdso.h> 33#include <machine/atomic.h> 34#endif 35 36#include <err.h> 37#include <errno.h> 38#include <signal.h> 39#include <stdbool.h> 40#include <stdint.h> 41 42#if ARC4RANDOM_FXRNG != 0 43/* 44 * The kernel root seed version is a 64-bit counter, but we truncate it to a 45 * 32-bit value in userspace for the convenience of 32-bit platforms. 32-bit 46 * rollover is not possible with the current reseed interval (1 hour at limit) 47 * without dynamic addition of new random devices (which also force a reseed in 48 * the FXRNG design). We don't have any dynamic device mechanism at this 49 * time, and anyway something else is very wrong if billions of new devices are 50 * being added. 51 * 52 * As is, it takes roughly 456,000 years of runtime to overflow the 32-bit 53 * version. 54 */ 55#define fxrng_load_acq_generation(x) atomic_load_acq_32(x) 56static struct vdso_fxrng_generation_1 *vdso_fxrngp; 57#endif 58 59static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; 60#define _ARC4_LOCK() \ 61 do { \ 62 if (__isthreaded) \ 63 _pthread_mutex_lock(&arc4random_mtx); \ 64 } while (0) 65 66#define _ARC4_UNLOCK() \ 67 do { \ 68 if (__isthreaded) \ 69 _pthread_mutex_unlock(&arc4random_mtx); \ 70 } while (0) 71 72static inline void 73_getentropy_fail(void) 74{ 75 raise(SIGKILL); 76} 77 78static inline void 79_rs_initialize_fxrng(void) 80{ 81#if ARC4RANDOM_FXRNG != 0 82 struct vdso_fxrng_generation_1 *fxrngp; 83 int error; 84 85 error = _elf_aux_info(AT_FXRNG, &fxrngp, sizeof(fxrngp)); 86 if (error != 0) { 87 /* 88 * New userspace on an old or !RANDOM_FENESTRASX kernel; or an 89 * arch that does not have a VDSO page. 90 */ 91 return; 92 } 93 94 /* Old userspace on newer kernel. */ 95 if (fxrngp->fx_vdso_version != VDSO_FXRNG_VER_1) 96 return; 97 98 vdso_fxrngp = fxrngp; 99#endif 100} 101 102static inline int 103_rs_allocate(struct _rs **rsp, struct _rsx **rsxp) 104{ 105 struct { 106 struct _rs rs; 107 struct _rsx rsx; 108 } *p; 109 110 if ((p = mmap(NULL, sizeof(*p), PROT_READ|PROT_WRITE, 111 MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) 112 return (-1); 113 /* Allow bootstrapping arc4random.c on Linux/macOS */ 114#ifdef INHERIT_ZERO 115 if (minherit(p, sizeof(*p), INHERIT_ZERO) == -1) { 116 munmap(p, sizeof(*p)); 117 return (-1); 118 } 119#endif 120 121 _rs_initialize_fxrng(); 122 123 *rsp = &p->rs; 124 *rsxp = &p->rsx; 125 return (0); 126} 127 128/* 129 * This isn't only detecting fork. We're also using the existing callback from 130 * _rs_stir_if_needed() to force arc4random(3) to reseed if the fenestrasX root 131 * seed version has changed. (That is, the root random(4) has reseeded from 132 * pooled entropy.) 133 */ 134static inline void 135_rs_forkdetect(void) 136{ 137 /* Detect fork (minherit(2) INHERIT_ZERO). */ 138 if (__predict_false(rs == NULL || rsx == NULL)) 139 return; 140#if ARC4RANDOM_FXRNG != 0 141 /* If present, detect kernel FenestrasX seed version change. */ 142 if (vdso_fxrngp == NULL) 143 return; 144 if (__predict_true(rsx->rs_seed_generation == 145 fxrng_load_acq_generation(&vdso_fxrngp->fx_generation32))) 146 return; 147#endif 148 /* Invalidate rs_buf to force "stir" (reseed). */ 149 memset(rs, 0, sizeof(*rs)); 150} 151