From 40c49c2d1244afbe480619d82d2783e811805d99 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Sat, 11 Sep 2021 15:55:04 +0100 Subject: [PATCH 1/2] ReseedingRng: more robust fork handling --- src/rngs/adapter/reseeding.rs | 26 ++++++++++++++++++++------ src/rngs/thread.rs | 5 +++-- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/rngs/adapter/reseeding.rs b/src/rngs/adapter/reseeding.rs index 70b0b82307f..ae3fcbb2fc2 100644 --- a/src/rngs/adapter/reseeding.rs +++ b/src/rngs/adapter/reseeding.rs @@ -22,10 +22,10 @@ use rand_core::{CryptoRng, Error, RngCore, SeedableRng}; /// /// - On a manual call to [`reseed()`]. /// - After `clone()`, the clone will be reseeded on first use. -/// - After a process is forked, the RNG in the child process is reseeded within -/// the next few generated values, depending on the block size of the -/// underlying PRNG. For ChaCha and Hc128 this is a maximum of -/// 15 `u32` values before reseeding. +/// - When a process is forked on UNIX, the RNGs in both the parent and child +/// processes will be reseeded just before the next call to +/// [`BlockRngCore::generate`], i.e. "soon". For ChaCha and Hc128 this is a +/// maximum of fifteen `u32` values before reseeding. /// - After the PRNG has generated a configurable number of random bytes. /// /// # When should reseeding after a fixed number of generated bytes be used? @@ -43,6 +43,12 @@ use rand_core::{CryptoRng, Error, RngCore, SeedableRng}; /// Use [`ReseedingRng::new`] with a `threshold` of `0` to disable reseeding /// after a fixed number of generated bytes. /// +/// # Limitations +/// +/// It is recommended that a `ReseedingRng` (including `ThreadRng`) not be used +/// from a fork handler. +/// Use `OsRng` or `getrandom`, or defer your use of the RNG until later. +/// /// # Error handling /// /// Although unlikely, reseeding the wrapped PRNG can fail. `ReseedingRng` will @@ -310,8 +316,16 @@ mod fork { pub fn register_fork_handler() { static REGISTER: Once = Once::new(); - REGISTER.call_once(|| unsafe { - libc::pthread_atfork(None, None, Some(fork_handler)); + REGISTER.call_once(|| { + // Bump the counter before and after forking (see #1169): + let ret = unsafe { libc::pthread_atfork( + Some(fork_handler), + Some(fork_handler), + Some(fork_handler), + ) }; + if ret != 0 { + panic!("libc::pthread_atfork failed with code {}", ret); + } }); } } diff --git a/src/rngs/thread.rs b/src/rngs/thread.rs index 13511e3ed2a..baebb1d99c7 100644 --- a/src/rngs/thread.rs +++ b/src/rngs/thread.rs @@ -40,8 +40,9 @@ const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64; /// A reference to the thread-local generator /// /// An instance can be obtained via [`thread_rng`] or via `ThreadRng::default()`. -/// This handle is safe to use everywhere (including thread-local destructors) -/// but cannot be passed between threads (is not `Send` or `Sync`). +/// This handle is safe to use everywhere (including thread-local destructors), +/// though it is recommended not to use inside a fork handler. +/// The handle cannot be passed between threads (is not `Send` or `Sync`). /// /// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance /// and is automatically seeded from [`OsRng`]. From 0435f0fff3f47353c8ecedea6d5f9111ddd4b272 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Sat, 11 Sep 2021 16:55:53 +0100 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e87add21bc..11bd4eefcf8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,9 @@ You may also find the [Upgrade Guide](https://rust-random.github.io/book/update. ## [0.8.5] - unreleased ### Fixes -- Fix build on non-32/64-bit architectures (#1144) +- Fix build on non-32/64-bit architectures (#1144) +- Check `libc::pthread_atfork` return value with panic on error (#1178) +- More robust reseeding in case `ReseedingRng` is used from a fork handler (#1178) ## [0.8.4] - 2021-06-15 ### Additions