about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBlackHoleFox <blackholefoxdev@gmail.com>2023-10-01 10:55:24 -0500
committerBlackHoleFox <blackholefoxdev@gmail.com>2023-10-23 20:35:45 -0500
commit090e9de5708388a21d66adbec91c871a48ac355e (patch)
tree311f1c01a150883e8c9a33172400a848178aa720
parentf654229c27267334023a22233795b88b75fc340e (diff)
downloadrust-090e9de5708388a21d66adbec91c871a48ac355e.tar.gz
rust-090e9de5708388a21d66adbec91c871a48ac355e.zip
Remove Apple RNG fallbacks and simplify implementation
-rw-r--r--library/std/src/sys/unix/mod.rs1
-rw-r--r--library/std/src/sys/unix/rand.rs109
2 files changed, 52 insertions, 58 deletions
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index da05620fd16..4b28f6feba5 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -415,7 +415,6 @@ cfg_if::cfg_if! {
     } else if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] {
         #[link(name = "System")]
         #[link(name = "objc")]
-        #[link(name = "Security", kind = "framework")]
         #[link(name = "Foundation", kind = "framework")]
         extern "C" {}
     } else if #[cfg(target_os = "fuchsia")] {
diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs
index bdf725fbe5a..2825d167742 100644
--- a/library/std/src/sys/unix/rand.rs
+++ b/library/std/src/sys/unix/rand.rs
@@ -151,40 +151,65 @@ mod imp {
     }
 }
 
-#[cfg(target_os = "macos")]
+#[cfg(target_vendor = "apple")]
 mod imp {
-    use crate::fs::File;
-    use crate::io::Read;
-    use crate::sys::os::errno;
-    use crate::sys::weak::weak;
+    use crate::io;
     use libc::{c_int, c_void, size_t};
 
-    fn getentropy_fill_bytes(v: &mut [u8]) -> bool {
-        weak!(fn getentropy(*mut c_void, size_t) -> c_int);
-
-        getentropy
-            .get()
-            .map(|f| {
-                // getentropy(2) permits a maximum buffer size of 256 bytes
-                for s in v.chunks_mut(256) {
-                    let ret = unsafe { f(s.as_mut_ptr() as *mut c_void, s.len()) };
-                    if ret == -1 {
-                        panic!("unexpected getentropy error: {}", errno());
-                    }
-                }
-                true
-            })
-            .unwrap_or(false)
+    #[inline(always)]
+    fn random_failure() -> ! {
+        panic!("unexpected random generation error: {}", io::Error::last_os_error());
     }
 
-    pub fn fill_bytes(v: &mut [u8]) {
-        if getentropy_fill_bytes(v) {
-            return;
+    #[cfg(target_os = "macos")]
+    fn getentropy_fill_bytes(v: &mut [u8]) {
+        extern "C" {
+            fn getentropy(bytes: *mut c_void, count: size_t) -> c_int;
         }
 
-        // for older macos which doesn't support getentropy
-        let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
-        file.read_exact(v).expect("failed to read /dev/urandom")
+        // getentropy(2) permits a maximum buffer size of 256 bytes
+        for s in v.chunks_mut(256) {
+            let ret = unsafe { getentropy(s.as_mut_ptr().cast(), s.len()) };
+            if ret == -1 {
+                random_failure()
+            }
+        }
+    }
+
+    #[cfg(not(target_os = "macos"))]
+    fn ccrandom_fill_bytes(v: &mut [u8]) {
+        extern "C" {
+            fn CCRandomGenerateBytes(bytes: *mut c_void, count: size_t) -> c_int;
+        }
+
+        let ret = unsafe { CCRandomGenerateBytes(v.as_mut_ptr().cast(), v.len()) };
+        if ret == -1 {
+            random_failure()
+        }
+    }
+
+    pub fn fill_bytes(v: &mut [u8]) {
+        // All supported versions of macOS (10.12+) support getentropy.
+        //
+        // `getentropy` is measurably faster (via Divan) then the other alternatives so its preferred
+        // when usable.
+        #[cfg(target_os = "macos")]
+        getentropy_fill_bytes(v);
+
+        // On Apple platforms, `CCRandomGenerateBytes` and `SecRandomCopyBytes` simply
+        // call into `CCRandomCopyBytes` with `kCCRandomDefault`. `CCRandomCopyBytes`
+        // manages a CSPRNG which is seeded from the kernel's CSPRNG and which runs on
+        // its own thread accessed via GCD. This seems needlessly heavyweight for our purposes
+        // so we only use it on non-Mac OSes where the better entrypoints are blocked.
+        //
+        // `CCRandomGenerateBytes` is used instead of `SecRandomCopyBytes` because the former is accessible
+        // via `libSystem` (libc) while the other needs to link to `Security.framework`.
+        //
+        // Note that while `getentropy` has a available attribute in the macOS headers, the lack
+        // of a header in the iOS (and others) SDK means that its can cause app store rejections.
+        // Just use `CCRandomGenerateBytes` instead.
+        #[cfg(not(target_os = "macos"))]
+        ccrandom_fill_bytes(v);
     }
 }
 
@@ -203,36 +228,6 @@ mod imp {
     }
 }
 
-// On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
-// `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
-// from `/dev/random` and which runs on its own thread accessed via GCD.
-// This seems needlessly heavyweight for the purposes of generating two u64s
-// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
-// only used on iOS where direct access to `/dev/urandom` is blocked by the
-// sandbox.
-#[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))]
-mod imp {
-    use crate::io;
-    use crate::ptr;
-    use libc::{c_int, size_t};
-
-    enum SecRandom {}
-
-    #[allow(non_upper_case_globals)]
-    const kSecRandomDefault: *const SecRandom = ptr::null();
-
-    extern "C" {
-        fn SecRandomCopyBytes(rnd: *const SecRandom, count: size_t, bytes: *mut u8) -> c_int;
-    }
-
-    pub fn fill_bytes(v: &mut [u8]) {
-        let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, v.len(), v.as_mut_ptr()) };
-        if ret == -1 {
-            panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
-        }
-    }
-}
-
 // FIXME: once the 10.x release becomes the minimum, this can be dropped for simplification.
 #[cfg(target_os = "netbsd")]
 mod imp {