Skip to content

Commit 9a00a43

Browse files
authored
Merge pull request #1178 from dhardy/work
ReseedingRng: more robust fork handling
2 parents fcc5baf + 0435f0f commit 9a00a43

File tree

3 files changed

+26
-9
lines changed

3 files changed

+26
-9
lines changed

CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.
1010

1111
## [0.8.5] - unreleased
1212
### Fixes
13-
- Fix build on non-32/64-bit architectures (#1144)
13+
- Fix build on non-32/64-bit architectures (#1144)
14+
- Check `libc::pthread_atfork` return value with panic on error (#1178)
15+
- More robust reseeding in case `ReseedingRng` is used from a fork handler (#1178)
1416

1517
## [0.8.4] - 2021-06-15
1618
### Additions

src/rngs/adapter/reseeding.rs

+20-6
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
2222
///
2323
/// - On a manual call to [`reseed()`].
2424
/// - After `clone()`, the clone will be reseeded on first use.
25-
/// - After a process is forked, the RNG in the child process is reseeded within
26-
/// the next few generated values, depending on the block size of the
27-
/// underlying PRNG. For ChaCha and Hc128 this is a maximum of
28-
/// 15 `u32` values before reseeding.
25+
/// - When a process is forked on UNIX, the RNGs in both the parent and child
26+
/// processes will be reseeded just before the next call to
27+
/// [`BlockRngCore::generate`], i.e. "soon". For ChaCha and Hc128 this is a
28+
/// maximum of fifteen `u32` values before reseeding.
2929
/// - After the PRNG has generated a configurable number of random bytes.
3030
///
3131
/// # When should reseeding after a fixed number of generated bytes be used?
@@ -43,6 +43,12 @@ use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
4343
/// Use [`ReseedingRng::new`] with a `threshold` of `0` to disable reseeding
4444
/// after a fixed number of generated bytes.
4545
///
46+
/// # Limitations
47+
///
48+
/// It is recommended that a `ReseedingRng` (including `ThreadRng`) not be used
49+
/// from a fork handler.
50+
/// Use `OsRng` or `getrandom`, or defer your use of the RNG until later.
51+
///
4652
/// # Error handling
4753
///
4854
/// Although unlikely, reseeding the wrapped PRNG can fail. `ReseedingRng` will
@@ -310,8 +316,16 @@ mod fork {
310316

311317
pub fn register_fork_handler() {
312318
static REGISTER: Once = Once::new();
313-
REGISTER.call_once(|| unsafe {
314-
libc::pthread_atfork(None, None, Some(fork_handler));
319+
REGISTER.call_once(|| {
320+
// Bump the counter before and after forking (see #1169):
321+
let ret = unsafe { libc::pthread_atfork(
322+
Some(fork_handler),
323+
Some(fork_handler),
324+
Some(fork_handler),
325+
) };
326+
if ret != 0 {
327+
panic!("libc::pthread_atfork failed with code {}", ret);
328+
}
315329
});
316330
}
317331
}

src/rngs/thread.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64;
4040
/// A reference to the thread-local generator
4141
///
4242
/// An instance can be obtained via [`thread_rng`] or via `ThreadRng::default()`.
43-
/// This handle is safe to use everywhere (including thread-local destructors)
44-
/// but cannot be passed between threads (is not `Send` or `Sync`).
43+
/// This handle is safe to use everywhere (including thread-local destructors),
44+
/// though it is recommended not to use inside a fork handler.
45+
/// The handle cannot be passed between threads (is not `Send` or `Sync`).
4546
///
4647
/// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance
4748
/// and is automatically seeded from [`OsRng`].

0 commit comments

Comments
 (0)