diff --git a/src/liblibc b/src/liblibc index 9863d5645fc4d..4b9b07c71997d 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 9863d5645fc4d1be789d03bcf58c1b3cfafbba39 +Subproject commit 4b9b07c71997da23d5d1e3035cd16a5855b94ecc diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index 7a4a0f96b3090..21e60420c186a 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -47,6 +47,7 @@ //! if the entropy pool is very small, such as immediately after first booting. //! Linux 3.17 added the `getrandom(2)` system call which solves the issue: it blocks if entropy //! pool is not initialized yet, but it does not block once initialized. +//! `getrandom(2)` was based on `getentropy(2)`, an existing system call in OpenBSD. //! `OsRng` tries to use `getrandom(2)` if available, and use `/dev/urandom` fallback if not. //! If an application does not have `getrandom` and likely to be run soon after first booting, //! or on a system with very few entropy sources, one should consider using `/dev/random` via diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index c4f59d51f5dad..13965ce810ddc 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -13,7 +13,7 @@ pub use self::imp::OsRng; -#[cfg(all(unix, not(target_os = "ios")))] +#[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))] mod imp { use self::OsRngInner::*; @@ -131,6 +131,7 @@ mod imp { /// - Windows: calls `CryptGenRandom`, using the default cryptographic /// service provider with the `PROV_RSA_FULL` type. /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed. + /// - OpenBSD: uses the `getentropy(2)` system call. /// /// This does not block. pub struct OsRng { @@ -178,6 +179,63 @@ mod imp { } } +#[cfg(target_os = "openbsd")] +mod imp { + use io; + use mem; + use libc::c_long; + use sys::os::errno; + use rand::Rng; + + /// A random number generator that retrieves randomness straight from + /// the operating system. Platform sources: + /// + /// - Unix-like systems (Linux, Android, Mac OSX): read directly from + /// `/dev/urandom`, or from `getrandom(2)` system call if available. + /// - Windows: calls `CryptGenRandom`, using the default cryptographic + /// service provider with the `PROV_RSA_FULL` type. + /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed. + /// - OpenBSD: uses the `getentropy(2)` system call. + /// + /// This does not block. + pub struct OsRng { + // dummy field to ensure that this struct cannot be constructed outside + // of this module + _dummy: (), + } + + impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> io::Result { + Ok(OsRng { _dummy: () }) + } + } + + impl Rng for OsRng { + fn next_u32(&mut self) -> u32 { + let mut v = [0; 4]; + self.fill_bytes(&mut v); + unsafe { mem::transmute(v) } + } + fn next_u64(&mut self) -> u64 { + let mut v = [0; 8]; + self.fill_bytes(&mut v); + unsafe { mem::transmute(v) } + } + fn fill_bytes(&mut self, v: &mut [u8]) { + // getentropy(2) permits a maximum buffer size of 256 bytes + for s in v.chunks_mut(256) { + let ret = unsafe { + libc::syscall(libc::NR_GETENTROPY, s.as_mut_ptr(), s.len()) + }; + if ret == -1 { + panic!("unexpected getentropy error: {}", errno()); + } + } + } + } +} + #[cfg(target_os = "ios")] mod imp { #[cfg(stage0)] use prelude::v1::*; @@ -196,6 +254,7 @@ mod imp { /// - Windows: calls `CryptGenRandom`, using the default cryptographic /// service provider with the `PROV_RSA_FULL` type. /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed. + /// - OpenBSD: uses the `getentropy(2)` system call. /// /// This does not block. pub struct OsRng { @@ -261,6 +320,7 @@ mod imp { /// - Windows: calls `CryptGenRandom`, using the default cryptographic /// service provider with the `PROV_RSA_FULL` type. /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed. + /// - OpenBSD: uses the `getentropy(2)` system call. /// /// This does not block. pub struct OsRng {