pub fn hashmap_random_keys() -> (u64, u64) {
let mut v = (0, 0);
unsafe {
- let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8,
- mem::size_of_val(&v));
+ let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8, mem::size_of_val(&v));
imp::fill_bytes(view);
}
- return v
+ v
}
-#[cfg(all(unix,
- not(target_os = "ios"),
- not(target_os = "openbsd"),
- not(target_os = "freebsd"),
- not(target_os = "fuchsia")))]
+#[cfg(all(
+ unix,
+ not(target_os = "macos"),
+ not(target_os = "ios"),
+ not(target_os = "openbsd"),
+ not(target_os = "freebsd"),
+ not(target_os = "netbsd"),
+ not(target_os = "fuchsia"),
+ not(target_os = "redox")
+))]
mod imp {
use crate::fs::File;
use crate::io::Read;
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
- fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool { false }
+ fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool {
+ false
+ }
#[cfg(any(target_os = "linux", target_os = "android"))]
fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
let err = errno() as libc::c_int;
if err == libc::EINTR {
continue;
- } else if err == libc::ENOSYS {
+ } else if err == libc::ENOSYS || err == libc::EPERM {
+ // Fall back to reading /dev/urandom if `getrandom` is not
+ // supported on the current kernel.
+ //
+ // Also fall back in case it is disabled by something like
+ // seccomp or inside of virtual machines.
GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
return false;
} else if err == libc::EAGAIN {
}
}
+#[cfg(target_os = "macos")]
+mod imp {
+ use crate::fs::File;
+ use crate::io::Read;
+ use crate::sys::os::errno;
+ 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)
+ }
+
+ pub fn fill_bytes(v: &mut [u8]) {
+ if getentropy_fill_bytes(v) {
+ return;
+ }
+
+ // 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")
+ }
+}
+
#[cfg(target_os = "openbsd")]
mod imp {
use crate::sys::os::errno;
pub fn fill_bytes(v: &mut [u8]) {
// getentropy(2) permits a maximum buffer size of 256 bytes
for s in v.chunks_mut(256) {
- let ret = unsafe {
- libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
- };
+ let ret = unsafe { libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len()) };
if ret == -1 {
panic!("unexpected getentropy error: {}", errno());
}
}
}
+// 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(target_os = "ios")]
mod imp {
use crate::io;
#[allow(non_upper_case_globals)]
const kSecRandomDefault: *const SecRandom = ptr::null();
- extern {
- fn SecRandomCopyBytes(rnd: *const SecRandom,
- count: size_t,
- bytes: *mut u8) -> c_int;
+ 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())
- };
+ 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());
+ panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
}
}
}
-#[cfg(target_os = "freebsd")]
+#[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
mod imp {
use crate::ptr;
for s in v.chunks_mut(256) {
let mut s_len = s.len();
let ret = unsafe {
- libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
- s.as_mut_ptr() as *mut _, &mut s_len,
- ptr::null(), 0)
+ libc::sysctl(
+ mib.as_ptr(),
+ mib.len() as libc::c_uint,
+ s.as_mut_ptr() as *mut _,
+ &mut s_len,
+ ptr::null(),
+ 0,
+ )
};
if ret == -1 || s_len != s.len() {
- panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
- ret, s.len(), s_len);
+ panic!(
+ "kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
+ ret,
+ s.len(),
+ s_len
+ );
}
}
}
#[cfg(target_os = "fuchsia")]
mod imp {
#[link(name = "zircon")]
- extern {
+ extern "C" {
fn zx_cprng_draw(buffer: *mut u8, len: usize);
}
unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
}
}
+
+#[cfg(target_os = "redox")]
+mod imp {
+ use crate::fs::File;
+ use crate::io::Read;
+
+ pub fn fill_bytes(v: &mut [u8]) {
+ // Open rand:, read from it, and close it again.
+ let mut file = File::open("rand:").expect("failed to open rand:");
+ file.read_exact(v).expect("failed to read rand:")
+ }
+}