about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-05-20 23:11:12 +0000
committerbors <bors@rust-lang.org>2022-05-20 23:11:12 +0000
commite57884b6e96bede12447e21edcdc92fcac59ee46 (patch)
tree6a3124d7819e7ff58a024337a72d8246e078b6bd
parente6a4afc3af2d2a53f91fc8a77bdfe94bea375b29 (diff)
parent18a9d58266dfb86a3e3e6b53a42798dd4348d93b (diff)
downloadrust-e57884b6e96bede12447e21edcdc92fcac59ee46.tar.gz
rust-e57884b6e96bede12447e21edcdc92fcac59ee46.zip
Auto merge of #95824 - zx2c4-forks:grnd_insecure, r=thomcc
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.
-rw-r--r--Cargo.lock4
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/src/sys/unix/rand.rs15
3 files changed, 18 insertions, 3 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 2f143b097b7..21902888e88 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 d0d7d480fe8..95506fc1eb9 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" }
diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs
index 17e8efbe097..ea6df724713 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) }
     }