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 <cardoe@cardoe.com>
This commit is contained in:
Doug Goldstein 2016-04-16 15:25:56 -05:00
parent d00782494b
commit f875daca54

View File

@ -41,8 +41,10 @@ fn getrandom(buf: &mut [u8]) -> libc::c_long {
#[cfg(target_arch = "aarch64")]
const NR_GETRANDOM: libc::c_long = 278;
const GRND_NONBLOCK: libc::c_uint = 0x0001;
unsafe {
libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0)
libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)
}
}
@ -63,6 +65,11 @@ fn getrandom_fill_bytes(v: &mut [u8]) {
let err = errno() as libc::c_int;
if err == libc::EINTR {
continue;
} else if err == libc::EAGAIN {
let reader = File::open("/dev/urandom").expect("Unable to open /dev/urandom");
let mut reader_rng = ReaderRng::new(reader);
reader_rng.fill_bytes(& mut v[read..]);
read += v.len() as usize;
} else {
panic!("unexpected getrandom error: {}", err);
}