Ilya Maximets <[email protected]> writes: > On 10/28/26 8:14 PM, Aaron Conole wrote: >> Until now, utilities wishing access to a quality source of >> cryptographically secure random numbers would have to either >> forego security and just use the xorshift, or use one of a >> few very slow entropy options like get_entropy_or_die or >> OpenSSL's RAND_bytes() calls. Both of these are quality >> tested mechanisms, but the drawback is a very long time to >> execute (measured 10m iterations of rand_bytes taking >> roughly 5.14s to complete). >> >> This change adds a ChaCha20 based CSPRNG, which is known >> to be a high quality CSPRNG. The benefits are very fast >> execution time (the same 10m iterations only take 0.059s >> vs. the PRNG taking 0.018s). >> >> The following references can help with understanding the >> implementation: >> * RFC 8439, "ChaCha20 and Poly1305 for IETF Protocols" >> * libevent/arc4random.c, "Arc4 random number generator for OpenBSD." >> * glibc/stdlib/arc4random.c, "Psuedo random number generator" >> * Ben Tasker, "Writing (and backdooring) a ChaCha20 based CSPRNG" >> >> Assisted-by: LLM (claude, opencode, sonnet, opus, qwen3.8) >> Signed-off-by: Aaron Conole <[email protected]> >> --- >> v2->v3: >> * Update the verbiage around the implementations origins >> * Still exists the possiblity to abort on reseed >> * Fixed the CHACHA_K_INPUT comment >> * Fixed the chacha_sigma constant definition + comment >> * Documented maximum length in csprng_random_bytes >> * Introduce ovs_memzero that will clear memory without eliding >> the operations >> * Zero out the chacha20_block > > [...] > >> +struct csprng { >> + uint32_t state[16]; /* ChaCha20 state: >> + * constant|key|counter|nonce. */ >> + uint8_t buf[CSPRNG_BUFSZ]; /* Buffered keystream. */ >> + size_t pos; /* Next unused byte in 'buf'. */ >> + size_t served; /* Bytes served since last reseed. */ >> + int initialized; >> +}; >> + >> +/* ChaCha20 constant: "expand 32-byte k". Must be at least 16 >> bytes + NUL. */ >> +static const uint8_t chacha_sigma[] = "expand 32-byte k"; >> + >> +/* Current random state. */ >> +DEFINE_STATIC_PER_THREAD_DATA(struct csprng, cs_state, { .initialized = 0 >> }); > > LLMs complain that this state is preserved on fork. It's probably not a big > deal since there should be no cases where this code would be used before > forking > today, but maybe a bit of a trap. Maybe we should make xfork_at() > call a special > function that clears the state if it was initialized before?
It's a weird complaint. Honestly, there isn't much that we can do if someone does a fork() unless we explicitly are only calling forks from our library. But a code that can somehow do a fork() from a called library will still completely bypass any preventing measures we do here. The real way to do it safely is to use xmalloc() for the per-thread allocation and madvise(region, MADV_WIPEONFORK), I think. Then even if a library we link do does a fork(), the pages are guaranteed to be wiped. > It's not the only place where we can fork, but it may be better to convert > other > place into xfork if needed in the future. > > WDYT? > > Best regards, Ilya Maximets. _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
