From f4d409d6ed8265a269dda2b9f861a83b941959d7 Mon Sep 17 00:00:00 2001 From: Michael McConville Date: Wed, 16 Dec 2015 21:54:16 -0500 Subject: [PATCH 1/7] Use the getentropy(2) syscall on OpenBSD Rust already supports Linux's getrandom(2), which is very similar and was based on getentropy(2). This is a pretty clean, simple addition that uses the same approach as the iOS randomness API support. --- src/libstd/rand/mod.rs | 1 + src/libstd/rand/os.rs | 66 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index 7a4a0f96b309..21e60420c186 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 c4f59d51f5da..942e81905d30 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,67 @@ 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: (), + } + + extern "C" { + fn syscall(number: c_long, ...) -> c_long; + } + + 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]) { + let mut ret: c_long; + + // getentropy(2) permits a maximum buffer size of 256 bytes + for s in v.chunks_mut(256) { + unsafe { ret = syscall(7, s.as_mut_ptr(), s.len()); } + if ret == -1 { + panic!("unexpected getrandom error: {}", errno()); + } + } + } + } +} + #[cfg(target_os = "ios")] mod imp { #[cfg(stage0)] use prelude::v1::*; @@ -196,6 +258,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 +324,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 { From a51b70b8169df7d2199b100fae1c1da8f8d299e3 Mon Sep 17 00:00:00 2001 From: Michael McConville Date: Thu, 17 Dec 2015 00:17:31 -0500 Subject: [PATCH 2/7] Use the correct syscall name in panic message I copied it from the getrandom code but forgot to change the name. Reported by Sebastien Marie. --- src/libstd/rand/os.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 942e81905d30..a1c1244d3978 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -233,7 +233,7 @@ mod imp { for s in v.chunks_mut(256) { unsafe { ret = syscall(7, s.as_mut_ptr(), s.len()); } if ret == -1 { - panic!("unexpected getrandom error: {}", errno()); + panic!("unexpected getentropy error: {}", errno()); } } } From 3ee3a784bf4ff7157a84e16026f19c4bf059de47 Mon Sep 17 00:00:00 2001 From: Michael McConville Date: Thu, 17 Dec 2015 00:21:11 -0500 Subject: [PATCH 3/7] Use a const for getentropy(2)'s syscall number Reported by Sebastien Marie. --- src/libstd/rand/os.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index a1c1244d3978..7b1cbdb7eac6 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -208,6 +208,8 @@ mod imp { fn syscall(number: c_long, ...) -> c_long; } + const NR_GETENTROPY: libc::c_long = 7; + impl OsRng { /// Create a new `OsRng`. pub fn new() -> io::Result { @@ -231,7 +233,9 @@ mod imp { // getentropy(2) permits a maximum buffer size of 256 bytes for s in v.chunks_mut(256) { - unsafe { ret = syscall(7, s.as_mut_ptr(), s.len()); } + unsafe { + ret = syscall(NR_GETENTROPY, s.as_mut_ptr(), s.len()); + } if ret == -1 { panic!("unexpected getentropy error: {}", errno()); } From 5b282981d3b592f344d272b91dee2370fb71d35f Mon Sep 17 00:00:00 2001 From: Michael McConville Date: Thu, 17 Dec 2015 00:52:18 -0500 Subject: [PATCH 4/7] Simplify logic checking getentropy's return value --- src/libstd/rand/os.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 7b1cbdb7eac6..86116383c457 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -229,13 +229,11 @@ mod imp { unsafe { mem::transmute(v) } } fn fill_bytes(&mut self, v: &mut [u8]) { - let mut ret: c_long; - // getentropy(2) permits a maximum buffer size of 256 bytes for s in v.chunks_mut(256) { - unsafe { - ret = syscall(NR_GETENTROPY, s.as_mut_ptr(), s.len()); - } + let ret = unsafe { + syscall(NR_GETENTROPY, s.as_mut_ptr(), s.len()) + }; if ret == -1 { panic!("unexpected getentropy error: {}", errno()); } From 33113f86f4c4f191d1bf42642b1a7714c576e395 Mon Sep 17 00:00:00 2001 From: Michael McConville Date: Thu, 17 Dec 2015 02:13:48 -0500 Subject: [PATCH 5/7] Fix build by removing needless type prefix --- src/libstd/rand/os.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 86116383c457..9669528898eb 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -208,7 +208,7 @@ mod imp { fn syscall(number: c_long, ...) -> c_long; } - const NR_GETENTROPY: libc::c_long = 7; + const NR_GETENTROPY: c_long = 7; impl OsRng { /// Create a new `OsRng`. From 314062b70137a634dcf50e109120186e7542dced Mon Sep 17 00:00:00 2001 From: Michael McConville Date: Fri, 18 Dec 2015 22:37:54 -0500 Subject: [PATCH 6/7] Pull newer version of libc for NR_GETENTROPY --- src/liblibc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liblibc b/src/liblibc index 9863d5645fc4..4b9b07c71997 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 9863d5645fc4d1be789d03bcf58c1b3cfafbba39 +Subproject commit 4b9b07c71997da23d5d1e3035cd16a5855b94ecc From 9fde3e9b94e19426a319af33b330a5cb87340c46 Mon Sep 17 00:00:00 2001 From: Michael McConville Date: Fri, 18 Dec 2015 22:40:07 -0500 Subject: [PATCH 7/7] Use libc's syscall() and NR_GETENTROPY const --- src/libstd/rand/os.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 9669528898eb..13965ce810dd 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -204,12 +204,6 @@ mod imp { _dummy: (), } - extern "C" { - fn syscall(number: c_long, ...) -> c_long; - } - - const NR_GETENTROPY: c_long = 7; - impl OsRng { /// Create a new `OsRng`. pub fn new() -> io::Result { @@ -232,7 +226,7 @@ mod imp { // getentropy(2) permits a maximum buffer size of 256 bytes for s in v.chunks_mut(256) { let ret = unsafe { - syscall(NR_GETENTROPY, s.as_mut_ptr(), s.len()) + libc::syscall(libc::NR_GETENTROPY, s.as_mut_ptr(), s.len()) }; if ret == -1 { panic!("unexpected getentropy error: {}", errno());