Index: sys/dev/random/fenestrasX/fx_brng.c =================================================================== --- sys/dev/random/fenestrasX/fx_brng.c +++ sys/dev/random/fenestrasX/fx_brng.c @@ -48,6 +48,7 @@ #include #include +#include #include /* Index: sys/dev/random/fenestrasX/fx_main.c =================================================================== --- sys/dev/random/fenestrasX/fx_main.c +++ sys/dev/random/fenestrasX/fx_main.c @@ -88,7 +88,6 @@ * a while). * * Not yet implemented, not in scope, or todo: - * - arc4random(9) injection/replacement * - Userspace portions -- shared page, like timehands vdso? */ @@ -125,6 +124,7 @@ #include #include #include +#include #include struct fxrng_buffered_rng fxrng_root; @@ -142,7 +142,7 @@ * the root generation number >0. */ static void -fxrng_alg_read(uint8_t *output, size_t nbytes) +_fxrng_alg_read(uint8_t *output, size_t nbytes, uint64_t *seed_version_out) { struct fxrng_buffered_rng **pcpu_brng_p, *rng, *tmp; struct pcpu *pcpu; @@ -248,10 +248,32 @@ have_valid_rng: /* At this point we have a valid, initialized and seeded rng pointer. */ FXRNG_BRNG_LOCK(rng); + if (seed_version_out != NULL) + *seed_version_out = rng->brng_generation; fxrng_brng_read(rng, output, nbytes); FXRNG_BRNG_ASSERT_NOT(rng); } +static void +fxrng_alg_read(uint8_t *output, size_t nbytes) +{ + _fxrng_alg_read(output, nbytes, NULL); +} + +/* + * External API for arc4random(9) to fetch new key material and associated seed + * version in chacha20_randomstir(). + */ +void +read_random_key(void *output, size_t nbytes, uint64_t *seed_version_out) +{ + /* Ensure _fxrng_alg_read invariant. */ + if (__predict_false(atomic_load_acq_64(&fxrng_root_generation) == 0)) + (void)fxrng_alg_seeded(); + + _fxrng_alg_read(output, nbytes, seed_version_out); +} + static void fxrng_init_alg(void *dummy __unused) { Index: sys/dev/random/fenestrasX/fx_pool.c =================================================================== --- sys/dev/random/fenestrasX/fx_pool.c +++ sys/dev/random/fenestrasX/fx_pool.c @@ -52,6 +52,7 @@ #include #include #include +#include /* * Timer-based reseed interval growth factor and limit in seconds. (ยง 3.2) Index: sys/dev/random/fenestrasX/fx_priv.h =================================================================== --- sys/dev/random/fenestrasX/fx_priv.h +++ sys/dev/random/fenestrasX/fx_priv.h @@ -46,4 +46,3 @@ #endif extern struct fxrng_buffered_rng fxrng_root; -extern uint64_t __read_mostly fxrng_root_generation; Index: sys/dev/random/fenestrasX/fx_pub.h =================================================================== --- sys/dev/random/fenestrasX/fx_pub.h +++ sys/dev/random/fenestrasX/fx_pub.h @@ -28,22 +28,26 @@ */ #pragma once -#define ASSERT(x, fmt, ...) do { \ - if (__predict_true(x)) \ - break; \ - panic("%s:%d: Assertion '" #x "' in function %s failed: " fmt, \ - __FILE__, __LINE__, __func__, ## __VA_ARGS__); \ -} while (false) -#ifdef INVARIANTS -#define ASSERT_DEBUG(x, fmt, ...) do { \ - if (__predict_true(x)) \ - break; \ - panic("%s:%d: Assertion '" #x "' in function %s failed: " fmt, \ - __FILE__, __LINE__, __func__, ## __VA_ARGS__); \ -} while (false) -#else -#define ASSERT_DEBUG(...) -#endif +#include -extern struct fxrng_buffered_rng fxrng_root; +/* + * The root BRNG seed version, or generation. + * + * FenestrasX-aware downstream CSPRNGs (i.e., arc4random(9)) should track the + * generation number they seeded from, using the read_random_key(9) API below. + * If their current seed version is older than the root generation, they should + * reseed before producing output. + * + * The variable is read-only outside of the fenestrasX implementation and + * should be accessed using 'atomic_load_acq_64(&fxrng_root_generation)'. + * Reseeds are extremely infrequent, so callers may wish to hint to the + * compiler that a matching generation is the expected case, with + * __predict_true() or __predict_false(). + */ extern uint64_t __read_mostly fxrng_root_generation; + +/* + * A routine for generating seed/key material + * Bypasses random(4) for now, but conceivably could be incorporated into that. + */ +void read_random_key(void *buf, size_t nbytes, uint64_t *seed_version_out); Index: sys/dev/random/randomdev.c =================================================================== --- sys/dev/random/randomdev.c +++ sys/dev/random/randomdev.c @@ -387,8 +387,10 @@ selwakeuppri(&rsel, PUSER); wakeup(&random_alg_context); printf("random: unblocking device.\n"); +#ifndef RANDOM_FENESTRASX /* Do random(9) a favour while we are about it. */ (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, ARC4_ENTR_HAVE); +#endif } /* ARGSUSED */ Index: sys/libkern/arc4random.c =================================================================== --- sys/libkern/arc4random.c +++ sys/libkern/arc4random.c @@ -40,10 +40,14 @@ #include #include +#include + #include #include #include -#include +#ifdef RANDOM_FENESTRASX +#include +#endif #define CHACHA20_RESEED_BYTES 65536 #define CHACHA20_RESEED_SECONDS 300 @@ -52,7 +56,9 @@ CTASSERT(CHACHA20_KEYBYTES*8 >= CHACHA_MINKEYLEN); +#ifndef RANDOM_FENESTRASX int arc4rand_iniseed_state = ARC4_ENTR_NONE; +#endif MALLOC_DEFINE(M_CHACHA20RANDOM, "chacha20random", "chacha20random structures"); @@ -62,6 +68,9 @@ time_t t_reseed; u_int8_t m_buffer[CHACHA20_BUFFER_SIZE]; struct chacha_ctx ctx; +#ifdef RANDOM_FENESTRASX + uint64_t seed_version; +#endif } __aligned(CACHE_LINE_SIZE); static struct chacha20_s *chacha20inst = NULL; @@ -79,7 +88,10 @@ { struct timeval tv_now; u_int8_t key[CHACHA20_KEYBYTES]; +#ifdef RANDOM_FENESTRASX + uint64_t seed_version; +#else if (__predict_false(random_bypass_before_seeding && !is_random_seeded())) { SHA256_CTX ctx; uint64_t cc; @@ -106,6 +118,10 @@ "make sure 256 bits is still 256 bits"); SHA256_Final(key, &ctx); } else { +#endif +#ifdef RANDOM_FENESTRASX + read_random_key(key, CHACHA20_KEYBYTES, &seed_version); +#else /* * If the loader(8) did not have an entropy stash from the * previous shutdown to load, then we will block. The answer is @@ -117,6 +133,7 @@ */ read_random(key, CHACHA20_KEYBYTES); } +#endif getmicrouptime(&tv_now); mtx_lock(&chacha20->mtx); chacha_keysetup(&chacha20->ctx, key, CHACHA20_KEYBYTES*8); @@ -124,6 +141,9 @@ /* Reset for next reseed cycle. */ chacha20->t_reseed = tv_now.tv_sec + CHACHA20_RESEED_SECONDS; chacha20->numbytes = 0; +#ifdef RANDOM_FENESTRASX + chacha20->seed_version = seed_version; +#endif mtx_unlock(&chacha20->mtx); } @@ -173,9 +193,13 @@ u_int length; u_int8_t *p; +#ifdef RANDOM_FENESTRASX + if (__predict_false(reseed)) +#else if (__predict_false(reseed || (arc4rand_iniseed_state == ARC4_ENTR_HAVE && atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_HAVE, ARC4_ENTR_SEED)))) +#endif CHACHA20_FOREACH(chacha20) chacha20_randomstir(chacha20); @@ -185,8 +209,18 @@ if ((chacha20->numbytes > CHACHA20_RESEED_BYTES) || (tv.tv_sec > chacha20->t_reseed)) chacha20_randomstir(chacha20); - p = ptr; mtx_lock(&chacha20->mtx); +#ifdef RANDOM_FENESTRASX + if (__predict_false( + atomic_load_acq_64(&fxrng_root_generation) != chacha20->seed_version + )) { + mtx_unlock(&chacha20->mtx); + chacha20_randomstir(chacha20); + mtx_lock(&chacha20->mtx); + } +#endif + + p = ptr; while (len) { length = MIN(CHACHA20_BUFFER_SIZE, len); chacha_encrypt_bytes(&chacha20->ctx, chacha20->m_buffer, p, length); Index: sys/sys/libkern.h =================================================================== --- sys/sys/libkern.h +++ sys/sys/libkern.h @@ -118,10 +118,12 @@ static __inline long labs(long a) { return (a < 0 ? -a : a); } static __inline quad_t qabs(quad_t a) { return (a < 0 ? -a : a); } +#ifndef RANDOM_FENESTRASX #define ARC4_ENTR_NONE 0 /* Don't have entropy yet. */ #define ARC4_ENTR_HAVE 1 /* Have entropy. */ #define ARC4_ENTR_SEED 2 /* Reseeding. */ extern int arc4rand_iniseed_state; +#endif /* Prototypes for non-quad routines. */ struct malloc_type;