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/endian.h> 28 #include <sys/mman.h> 29 #if ARC4RANDOM_FXRNG != 0 30 #include <sys/time.h> /* for sys/vdso.h only. */ 31 #include <sys/vdso.h> 32 #include <machine/atomic.h> 33 #endif 34 35 #include <err.h> 36 #include <errno.h> 37 #include <signal.h> 38 #include <stdbool.h> 39 #include <stdint.h> 40 41 #if ARC4RANDOM_FXRNG != 0 42 /* 43 * The kernel root seed version is a 64-bit counter, but we truncate it to a 44 * 32-bit value in userspace for the convenience of 32-bit platforms. 32-bit 45 * rollover is not possible with the current reseed interval (1 hour at limit) 46 * without dynamic addition of new random devices (which also force a reseed in 47 * the FXRNG design). We don't have any dynamic device mechanism at this 48 * time, and anyway something else is very wrong if billions of new devices are 49 * being added. 50 * 51 * As is, it takes roughly 456,000 years of runtime to overflow the 32-bit 52 * version. 53 */ 54 #define fxrng_load_acq_generation(x) atomic_load_acq_32(x) 55 static struct vdso_fxrng_generation_1 *vdso_fxrngp; 56 #endif 57 58 static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; 59 #define _ARC4_LOCK() \ 60 do { \ 61 if (__isthreaded) \ 62 _pthread_mutex_lock(&arc4random_mtx); \ 63 } while (0) 64 65 #define _ARC4_UNLOCK() \ 66 do { \ 67 if (__isthreaded) \ 68 _pthread_mutex_unlock(&arc4random_mtx); \ 69 } while (0) 70 71 static inline void 72 _getentropy_fail(void) 73 { 74 raise(SIGKILL); 75 } 76 77 static inline void 78 _rs_initialize_fxrng(void) 79 { 80 #if ARC4RANDOM_FXRNG != 0 81 struct vdso_fxrng_generation_1 *fxrngp; 82 int error; 83 84 error = _elf_aux_info(AT_FXRNG, &fxrngp, sizeof(fxrngp)); 85 if (error != 0) { 86 /* 87 * New userspace on an old or !RANDOM_FENESTRASX kernel; or an 88 * arch that does not have a VDSO page. 89 */ 90 return; 91 } 92 93 /* Old userspace on newer kernel. */ 94 if (fxrngp->fx_vdso_version != VDSO_FXRNG_VER_1) 95 return; 96 97 vdso_fxrngp = fxrngp; 98 #endif 99 } 100 101 static inline int 102 _rs_allocate(struct _rs **rsp, struct _rsx **rsxp) 103 { 104 struct { 105 struct _rs rs; 106 struct _rsx rsx; 107 } *p; 108 109 if ((p = mmap(NULL, sizeof(*p), PROT_READ|PROT_WRITE, 110 MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) 111 return (-1); 112 /* Allow bootstrapping arc4random.c on Linux/macOS */ 113 #ifdef INHERIT_ZERO 114 if (minherit(p, sizeof(*p), INHERIT_ZERO) == -1) { 115 munmap(p, sizeof(*p)); 116 return (-1); 117 } 118 #endif 119 120 _rs_initialize_fxrng(); 121 122 *rsp = &p->rs; 123 *rsxp = &p->rsx; 124 return (0); 125 } 126 127 /* 128 * This isn't only detecting fork. We're also using the existing callback from 129 * _rs_stir_if_needed() to force arc4random(3) to reseed if the fenestrasX root 130 * seed version has changed. (That is, the root random(4) has reseeded from 131 * pooled entropy.) 132 */ 133 static inline void 134 _rs_forkdetect(void) 135 { 136 /* Detect fork (minherit(2) INHERIT_ZERO). */ 137 if (__predict_false(rs == NULL || rsx == NULL)) 138 return; 139 #if ARC4RANDOM_FXRNG != 0 140 /* If present, detect kernel FenestrasX seed version change. */ 141 if (vdso_fxrngp == NULL) 142 return; 143 if (__predict_true(rsx->rs_seed_generation == 144 fxrng_load_acq_generation(&vdso_fxrngp->fx_generation32))) 145 return; 146 #endif 147 /* Invalidate rs_buf to force "stir" (reseed). */ 148 memset(rs, 0, sizeof(*rs)); 149 } 150