Skip to content

Commit

Permalink
ReseedingRng: more robust fork handling
Browse files Browse the repository at this point in the history
  • Loading branch information
dhardy committed Sep 11, 2021
1 parent fcc5baf commit 40c49c2
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 8 deletions.
26 changes: 20 additions & 6 deletions src/rngs/adapter/reseeding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand All @@ -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
Expand Down Expand Up @@ -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);
}
});
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/rngs/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`].
Expand Down

0 comments on commit 40c49c2

Please sign in to comment.