From a13db3fc686f093a781e137bd53f3b810fde4fce Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 15 Apr 2019 06:29:57 -0400 Subject: [PATCH] initialize size class CSPRNGs from init CSPRNG This avoids making a huge number of getrandom system calls during initialization. The init CSPRNG is unmapped before initialization finishes and these are still reseeded from the OS. The purpose of the independent CSPRNGs is simply to avoid the massive performance hit of synchronization and there's no harm in doing it this way. Keeping around the init CSPRNG and reseeding from it would defeat the purpose of reseeding, and it isn't a measurable performance issue since it can just be tuned to reseed less often. --- h_malloc.c | 4 ++-- random.c | 10 ++++++++++ random.h | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/h_malloc.c b/h_malloc.c index 409fa2b..517af02 100644 --- a/h_malloc.c +++ b/h_malloc.c @@ -1093,7 +1093,7 @@ COLD static void init_slow_path(void) { struct region_allocator *ra = ro.region_allocator; mutex_init(&ra->lock); - random_state_init(&ra->rng); + random_state_init_from_random_state(&ra->rng, rng); ro.regions[0] = allocator_state->regions_a; ro.regions[1] = allocator_state->regions_b; ra->regions = ro.regions[0]; @@ -1116,7 +1116,7 @@ COLD static void init_slow_path(void) { struct size_class *c = &ro.size_class_metadata[arena][class]; mutex_init(&c->lock); - random_state_init(&c->rng); + random_state_init_from_random_state(&c->rng, rng); size_t bound = (REAL_CLASS_REGION_SIZE - CLASS_REGION_SIZE) / PAGE_SIZE - 1; size_t gap = (get_random_u64_uniform(rng, bound) + 1) * PAGE_SIZE; diff --git a/random.c b/random.c index ae242c4..c6dc759 100644 --- a/random.c +++ b/random.c @@ -44,6 +44,16 @@ void random_state_init(struct random_state *state) { state->reseed = 0; } +void random_state_init_from_random_state(struct random_state *state, struct random_state *source) { + u8 rnd[CHACHA_KEY_SIZE + CHACHA_IV_SIZE]; + get_random_bytes(source, rnd, sizeof(rnd)); + chacha_keysetup(&state->ctx, rnd); + chacha_ivsetup(&state->ctx, rnd + CHACHA_KEY_SIZE); + chacha_keystream_bytes(&state->ctx, state->cache, RANDOM_CACHE_SIZE); + state->index = 0; + state->reseed = 0; +} + static void refill(struct random_state *state) { if (state->reseed < RANDOM_RESEED_SIZE) { chacha_keystream_bytes(&state->ctx, state->cache, RANDOM_CACHE_SIZE); diff --git a/random.h b/random.h index 629b18a..14703bb 100644 --- a/random.h +++ b/random.h @@ -15,6 +15,7 @@ struct random_state { }; void random_state_init(struct random_state *state); +void random_state_init_from_random_state(struct random_state *state, struct random_state *source); void get_random_bytes(struct random_state *state, void *buf, size_t size); u16 get_random_u16(struct random_state *state); u16 get_random_u16_uniform(struct random_state *state, u16 bound);