From 204da52c34db2aa7e58e7b743c2bf2cdf485c048 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 20 May 2022 23:52:05 +0200 Subject: [PATCH 1/2] Update libc dependency of std to 0.2.126 This is required for the next commit, which uses libc::GRND_INSECURE. --- Cargo.lock | 4 ++-- library/std/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f143b097b7f4..21902888e8814 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2064,9 +2064,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" dependencies = [ "rustc-std-workspace-core", ] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index d0d7d480fe8e2..95506fc1eb9c8 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -15,7 +15,7 @@ cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } -libc = { version = "0.2.125", default-features = false, features = ['rustc-dep-of-std'] } +libc = { version = "0.2.126", default-features = false, features = ['rustc-dep-of-std'] } compiler_builtins = { version = "0.1.71" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } From 18a9d58266dfb86a3e3e6b53a42798dd4348d93b Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 8 Apr 2022 22:09:44 +0200 Subject: [PATCH 2/2] Use GRND_INSECURE instead of /dev/urandom when possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- library/std/src/sys/unix/rand.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs index 17e8efbe097ce..ea6df7247137c 100644 --- a/library/std/src/sys/unix/rand.rs +++ b/library/std/src/sys/unix/rand.rs @@ -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) } }