Use GRND_INSECURE instead of /dev/urandom when possible
From reading the source code, it appears like the desired semantic of std::unix::rand is to always provide some bytes and never block. For that reason GRND_NONBLOCK is checked before calling getrandom(0), so that getrandom(0) won't block. If it would block, then the function falls back to using /dev/urandom, which for the time being doesn't block. There are some drawbacks to using /dev/urandom, however, and so getrandom(GRND_INSECURE) was created as a replacement for this exact circumstance. getrandom(GRND_INSECURE) is the same as /dev/urandom, except: - It won't leave a warning in dmesg if used at early boot time, which is a common occurance (and the reason why I found this issue); - It won't introduce a tiny delay at early boot on newer kernels when /dev/urandom tries to opportunistically create jitter entropy; - It only requires 1 syscall, rather than 3. Other than that, it returns the same "quality" of randomness as /dev/urandom, and never blocks. It's only available on kernels ≥5.6, so we try to use it, cache the result of that attempt, and fall back to to the previous code if it didn't work.
This commit is contained in:
parent
204da52c34
commit
18a9d58266
@ -30,6 +30,9 @@ mod imp {
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
fn getrandom(buf: &mut [u8]) -> libc::ssize_t {
|
||||
use crate::sync::atomic::{AtomicBool, Ordering};
|
||||
use crate::sys::os::errno;
|
||||
|
||||
// A weak symbol allows interposition, e.g. for perf measurements that want to
|
||||
// disable randomness for consistency. Otherwise, we'll try a raw syscall.
|
||||
// (`getrandom` was added in glibc 2.25, musl 1.1.20, android API level 28)
|
||||
@ -41,6 +44,18 @@ mod imp {
|
||||
) -> libc::ssize_t
|
||||
}
|
||||
|
||||
// This provides the best quality random numbers available at the given moment
|
||||
// without ever blocking, and is preferable to falling back to /dev/urandom.
|
||||
static GRND_INSECURE_AVAILABLE: AtomicBool = AtomicBool::new(true);
|
||||
if GRND_INSECURE_AVAILABLE.load(Ordering::Relaxed) {
|
||||
let ret = unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_INSECURE) };
|
||||
if ret == -1 && errno() as libc::c_int == libc::EINVAL {
|
||||
GRND_INSECURE_AVAILABLE.store(false, Ordering::Relaxed);
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_NONBLOCK) }
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user