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) 56 static struct vdso_fxrng_generation_1 *vdso_fxrngp; 57 #endif 58 59 static 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 72 static inline void 73 _getentropy_fail(void) 74 { 75 raise(SIGKILL); 76 } 77 78 static 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 102 static 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 */ 134 static 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