Skip to content

Commit a36c419

Browse files
committed
Auto merge of #33086 - cardoe:non-blocking-rand-read, r=alexcrichton
rand: don't block before random pool is initialized If we attempt a read with getrandom() on Linux the syscall can block before the random pool is initialized unless the GRND_NONBLOCK flag is passed. This flag causes getrandom() to instead return EAGAIN while the pool is uninitialized. To avoid downstream users of crate or std functionality that have no ability to avoid this blocking behavior this change causes Rust to read bytes from /dev/urandom while getrandom() would block and once getrandom() is available to use that. Fixes #32953. Signed-off-by: Doug Goldstein <[email protected]>
2 parents 6301e22 + 61cbd07 commit a36c419

File tree

2 files changed

+20
-3
lines changed

2 files changed

+20
-3
lines changed

src/libstd/collections/hash/map.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,10 @@ fn test_resize_policy() {
202202
/// The hashes are all keyed by the thread-local random number generator
203203
/// on creation by default. This means that the ordering of the keys is
204204
/// randomized, but makes the tables more resistant to
205-
/// denial-of-service attacks (Hash DoS). This behavior can be
206-
/// overridden with one of the constructors.
205+
/// denial-of-service attacks (Hash DoS). No guarantees are made to the
206+
/// quality of the random data. The implementation uses the best available
207+
/// random data from your platform at the time of creation. This behavior
208+
/// can be overridden with one of the constructors.
207209
///
208210
/// It is required that the keys implement the `Eq` and `Hash` traits, although
209211
/// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`.

src/libstd/sys/unix/rand.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ mod imp {
4141
#[cfg(target_arch = "aarch64")]
4242
const NR_GETRANDOM: libc::c_long = 278;
4343

44+
const GRND_NONBLOCK: libc::c_uint = 0x0001;
45+
4446
unsafe {
45-
libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0)
47+
libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)
4648
}
4749
}
4850

@@ -63,6 +65,19 @@ mod imp {
6365
let err = errno() as libc::c_int;
6466
if err == libc::EINTR {
6567
continue;
68+
} else if err == libc::EAGAIN {
69+
// if getrandom() returns EAGAIN it would have blocked
70+
// because the non-blocking pool (urandom) has not
71+
// initialized in the kernel yet due to a lack of entropy
72+
// the fallback we do here is to avoid blocking applications
73+
// which could depend on this call without ever knowing
74+
// they do and don't have a work around. The PRNG of
75+
// /dev/urandom will still be used but not over a completely
76+
// full entropy pool
77+
let reader = File::open("/dev/urandom").expect("Unable to open /dev/urandom");
78+
let mut reader_rng = ReaderRng::new(reader);
79+
reader_rng.fill_bytes(& mut v[read..]);
80+
read += v.len() as usize;
6681
} else {
6782
panic!("unexpected getrandom error: {}", err);
6883
}

0 commit comments

Comments
 (0)