Index: head/lib/libc/gen/arc4random.c =================================================================== --- head/lib/libc/gen/arc4random.c (revision 366631) +++ head/lib/libc/gen/arc4random.c (revision 366632) @@ -1,243 +1,248 @@ /* $OpenBSD: arc4random.c,v 1.55 2019/03/24 17:56:54 deraadt Exp $ */ /* * Copyright (c) 1996, David Mazieres * Copyright (c) 2008, Damien Miller * Copyright (c) 2013, Markus Friedl * Copyright (c) 2014, Theo de Raadt * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * ChaCha based random number generator for OpenBSD. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #if defined(__FreeBSD__) #include #endif #include #include #include #include #include #include #include #include #include #include #include "libc_private.h" #include "un-namespace.h" #define CHACHA_EMBED #define KEYSTREAM_ONLY +#if defined(__FreeBSD__) +#define ARC4RANDOM_FXRNG 1 +#else +#define ARC4RANDOM_FXRNG 0 +#endif #include "chacha.c" #define minimum(a, b) ((a) < (b) ? (a) : (b)) #if defined(__GNUC__) || defined(_MSC_VER) #define inline __inline #else /* __GNUC__ || _MSC_VER */ #define inline #endif /* !__GNUC__ && !_MSC_VER */ #define KEYSZ 32 #define IVSZ 8 #define BLOCKSZ 64 #define RSBUFSZ (16*BLOCKSZ) /* Marked INHERIT_ZERO, so zero'd out in fork children. */ static struct _rs { size_t rs_have; /* valid bytes at end of rs_buf */ size_t rs_count; /* bytes till reseed */ } *rs; /* Maybe be preserved in fork children, if _rs_allocate() decides. */ static struct _rsx { chacha_ctx rs_chacha; /* chacha context for random keystream */ u_char rs_buf[RSBUFSZ]; /* keystream blocks */ #ifdef __FreeBSD__ uint32_t rs_seed_generation; /* 32-bit userspace RNG version */ #endif } *rsx; static inline int _rs_allocate(struct _rs **, struct _rsx **); static inline void _rs_forkdetect(void); #include "arc4random.h" static inline void _rs_rekey(u_char *dat, size_t datlen); static inline void _rs_init(u_char *buf, size_t n) { if (n < KEYSZ + IVSZ) return; if (rs == NULL) { if (_rs_allocate(&rs, &rsx) == -1) _exit(1); } chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8); chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ, NULL); } static void _rs_stir(void) { u_char rnd[KEYSZ + IVSZ]; #if defined(__FreeBSD__) bool need_init; /* * De-couple allocation (which locates the vdso_fxrngp pointer in * auxinfo) from initialization. This allows us to read the root seed * version before we fetch system entropy, maintaining the invariant * that the PRF was seeded with entropy from rs_seed_generation or a * later generation. But never seeded from an earlier generation. * This invariant prevents us from missing a root reseed event. */ need_init = false; if (rs == NULL) { if (_rs_allocate(&rs, &rsx) == -1) abort(); need_init = true; } /* * Transition period: new userspace on old kernel. This should become * a hard error at some point, if the scheme is adopted. */ if (vdso_fxrngp != NULL) rsx->rs_seed_generation = fxrng_load_acq_generation(&vdso_fxrngp->fx_generation32); #endif if (getentropy(rnd, sizeof rnd) == -1) _getentropy_fail(); #if !defined(__FreeBSD__) if (!rs) _rs_init(rnd, sizeof(rnd)); #else /* __FreeBSD__ */ assert(rs != NULL); if (need_init) _rs_init(rnd, sizeof(rnd)); #endif else _rs_rekey(rnd, sizeof(rnd)); explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */ /* invalidate rs_buf */ rs->rs_have = 0; memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); rs->rs_count = 1600000; } static inline void _rs_stir_if_needed(size_t len) { _rs_forkdetect(); if (!rs || rs->rs_count <= len) _rs_stir(); if (rs->rs_count <= len) rs->rs_count = 0; else rs->rs_count -= len; } static inline void _rs_rekey(u_char *dat, size_t datlen) { #ifndef KEYSTREAM_ONLY memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); #endif /* fill rs_buf with the keystream */ chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf, rsx->rs_buf, sizeof(rsx->rs_buf)); /* mix in optional user provided data */ if (dat) { size_t i, m; m = minimum(datlen, KEYSZ + IVSZ); for (i = 0; i < m; i++) rsx->rs_buf[i] ^= dat[i]; } /* immediately reinit for backtracking resistance */ _rs_init(rsx->rs_buf, KEYSZ + IVSZ); memset(rsx->rs_buf, 0, KEYSZ + IVSZ); rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ; } static inline void _rs_random_buf(void *_buf, size_t n) { u_char *buf = (u_char *)_buf; u_char *keystream; size_t m; _rs_stir_if_needed(n); while (n > 0) { if (rs->rs_have > 0) { m = minimum(n, rs->rs_have); keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have; memcpy(buf, keystream, m); memset(keystream, 0, m); buf += m; n -= m; rs->rs_have -= m; } if (rs->rs_have == 0) _rs_rekey(NULL, 0); } } static inline void _rs_random_u32(uint32_t *val) { u_char *keystream; _rs_stir_if_needed(sizeof(*val)); if (rs->rs_have < sizeof(*val)) _rs_rekey(NULL, 0); keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have; memcpy(val, keystream, sizeof(*val)); memset(keystream, 0, sizeof(*val)); rs->rs_have -= sizeof(*val); } uint32_t arc4random(void) { uint32_t val; _ARC4_LOCK(); _rs_random_u32(&val); _ARC4_UNLOCK(); return val; } void arc4random_buf(void *buf, size_t n) { _ARC4_LOCK(); _rs_random_buf(buf, n); _ARC4_UNLOCK(); } Index: head/lib/libc/gen/arc4random.h =================================================================== --- head/lib/libc/gen/arc4random.h (revision 366631) +++ head/lib/libc/gen/arc4random.h (revision 366632) @@ -1,143 +1,150 @@ /* $OpenBSD: arc4random.h,v 1.4 2015/01/15 06:57:18 deraadt Exp $ */ /* * Copyright (c) 1996, David Mazieres * Copyright (c) 2008, Damien Miller * Copyright (c) 2013, Markus Friedl * Copyright (c) 2014, Theo de Raadt * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ /* * Stub functions for portability. */ #include #include #include +#if ARC4RANDOM_FXRNG != 0 #include /* for sys/vdso.h only. */ #include #include +#endif #include #include #include #include #include +#if ARC4RANDOM_FXRNG != 0 /* * The kernel root seed version is a 64-bit counter, but we truncate it to a * 32-bit value in userspace for the convenience of 32-bit platforms. 32-bit * rollover is not possible with the current reseed interval (1 hour at limit) * without dynamic addition of new random devices (which also force a reseed in * the FXRNG design). We don't have any dynamic device mechanism at this * time, and anyway something else is very wrong if billions of new devices are * being added. * * As is, it takes roughly 456,000 years of runtime to overflow the 32-bit * version. */ #define fxrng_load_acq_generation(x) atomic_load_acq_32(x) static struct vdso_fxrng_generation_1 *vdso_fxrngp; +#endif static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; #define _ARC4_LOCK() \ do { \ if (__isthreaded) \ _pthread_mutex_lock(&arc4random_mtx); \ } while (0) #define _ARC4_UNLOCK() \ do { \ if (__isthreaded) \ _pthread_mutex_unlock(&arc4random_mtx); \ } while (0) static inline void _getentropy_fail(void) { raise(SIGKILL); } static inline void _rs_initialize_fxrng(void) { +#if ARC4RANDOM_FXRNG != 0 struct vdso_fxrng_generation_1 *fxrngp; int error; error = _elf_aux_info(AT_FXRNG, &fxrngp, sizeof(fxrngp)); if (error != 0) { /* * New userspace on an old or !RANDOM_FENESTRASX kernel; or an * arch that does not have a VDSO page. */ return; } /* Old userspace on newer kernel. */ if (fxrngp->fx_vdso_version != VDSO_FXRNG_VER_1) return; vdso_fxrngp = fxrngp; +#endif } static inline int _rs_allocate(struct _rs **rsp, struct _rsx **rsxp) { struct { struct _rs rs; struct _rsx rsx; } *p; if ((p = mmap(NULL, sizeof(*p), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) return (-1); /* Allow bootstrapping arc4random.c on Linux/macOS */ #ifdef INHERIT_ZERO if (minherit(p, sizeof(*p), INHERIT_ZERO) == -1) { munmap(p, sizeof(*p)); return (-1); } #endif _rs_initialize_fxrng(); *rsp = &p->rs; *rsxp = &p->rsx; return (0); } /* * This isn't only detecting fork. We're also using the existing callback from * _rs_stir_if_needed() to force arc4random(3) to reseed if the fenestrasX root * seed version has changed. (That is, the root random(4) has reseeded from * pooled entropy.) */ static inline void _rs_forkdetect(void) { /* Detect fork (minherit(2) INHERIT_ZERO). */ if (__predict_false(rs == NULL || rsx == NULL)) return; +#if ARC4RANDOM_FXRNG != 0 /* If present, detect kernel FenestrasX seed version change. */ if (vdso_fxrngp == NULL) return; if (__predict_true(rsx->rs_seed_generation == fxrng_load_acq_generation(&vdso_fxrngp->fx_generation32))) return; - +#endif /* Invalidate rs_buf to force "stir" (reseed). */ memset(rs, 0, sizeof(*rs)); }