Skip to content

Commit

Permalink
Merge pull request #1178 from dhardy/work
Browse files Browse the repository at this point in the history
ReseedingRng: more robust fork handling
  • Loading branch information
dhardy committed Sep 11, 2021
2 parents fcc5baf + 0435f0f commit 9a00a43
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 9 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Expand Up @@ -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
Expand Down
26 changes: 20 additions & 6 deletions src/rngs/adapter/reseeding.rs
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
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 9a00a43

Please sign in to comment.