From ef6aab2935a504787d01b1d9165d41b184a6027c Mon Sep 17 00:00:00 2001 From: Aaron Gallagher <_@habnab.it> Date: Fri, 29 Jul 2016 07:48:52 +0000 Subject: [PATCH 1/2] Reduce duplication in std::sys::unix::rand. There were a bunch of more-of-less the same few lines for doing a fill_bytes+transmute, and I didn't want to copy-paste it yet again. --- src/libstd/sys/unix/rand.rs | 54 +++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index 25a7a3ce50dc4..4e6d801d19176 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -10,14 +10,28 @@ pub use self::imp::OsRng; +use mem; + +fn next_u32(mut fill_buf: &mut FnMut(&mut [u8])) -> u32 { + let mut buf: [u8; 4] = [0; 4]; + fill_buf(&mut buf); + unsafe { mem::transmute::<[u8; 4], u32>(buf) } +} + +fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 { + let mut buf: [u8; 8] = [0; 8]; + fill_buf(&mut buf); + unsafe { mem::transmute::<[u8; 8], u64>(buf) } +} + #[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))] mod imp { use self::OsRngInner::*; + use super::{next_u32, next_u64}; use fs::File; use io; use libc; - use mem; use rand::Rng; use rand::reader::ReaderRng; use sys::os::errno; @@ -87,18 +101,6 @@ mod imp { } } - fn getrandom_next_u32() -> u32 { - let mut buf: [u8; 4] = [0; 4]; - getrandom_fill_bytes(&mut buf); - unsafe { mem::transmute::<[u8; 4], u32>(buf) } - } - - fn getrandom_next_u64() -> u64 { - let mut buf: [u8; 8] = [0; 8]; - getrandom_fill_bytes(&mut buf); - unsafe { mem::transmute::<[u8; 8], u64>(buf) } - } - #[cfg(all(target_os = "linux", any(target_arch = "x86_64", target_arch = "x86", @@ -163,13 +165,13 @@ mod imp { impl Rng for OsRng { fn next_u32(&mut self) -> u32 { match self.inner { - OsGetrandomRng => getrandom_next_u32(), + OsGetrandomRng => next_u32(&mut getrandom_fill_bytes), OsReaderRng(ref mut rng) => rng.next_u32(), } } fn next_u64(&mut self) -> u64 { match self.inner { - OsGetrandomRng => getrandom_next_u64(), + OsGetrandomRng => next_u64(&mut getrandom_fill_bytes), OsReaderRng(ref mut rng) => rng.next_u64(), } } @@ -184,9 +186,10 @@ mod imp { #[cfg(target_os = "openbsd")] mod imp { + use super::{next_u32, next_u64}; + use io; use libc; - use mem; use sys::os::errno; use rand::Rng; @@ -205,14 +208,10 @@ mod imp { impl Rng for OsRng { fn next_u32(&mut self) -> u32 { - let mut v = [0; 4]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } + next_u32(&mut |v| self.fill_bytes(v)) } fn next_u64(&mut self) -> u64 { - let mut v = [0; 8]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } + next_u64(&mut |v| self.fill_bytes(v)) } fn fill_bytes(&mut self, v: &mut [u8]) { // getentropy(2) permits a maximum buffer size of 256 bytes @@ -230,8 +229,9 @@ mod imp { #[cfg(target_os = "ios")] mod imp { + use super::{next_u32, next_u64}; + use io; - use mem; use ptr; use rand::Rng; use libc::{c_int, size_t}; @@ -265,14 +265,10 @@ mod imp { impl Rng for OsRng { fn next_u32(&mut self) -> u32 { - let mut v = [0; 4]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } + next_u32(&mut |v| self.fill_bytes(v)) } fn next_u64(&mut self) -> u64 { - let mut v = [0; 8]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } + next_u64(&mut |v| self.fill_bytes(v)) } fn fill_bytes(&mut self, v: &mut [u8]) { let ret = unsafe { From 0a70944e043db082353ed05cfa80994f6c56feae Mon Sep 17 00:00:00 2001 From: Aaron Gallagher <_@habnab.it> Date: Sun, 14 Aug 2016 08:27:11 +0000 Subject: [PATCH 2/2] Use the kernel arc4rand for FreeBSD OsRng. This means that /dev/urandom doesn't have to be opened. --- src/libstd/sys/unix/rand.rs | 53 ++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index 4e6d801d19176..e4ca8344ee287 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -24,7 +24,10 @@ fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 { unsafe { mem::transmute::<[u8; 8], u64>(buf) } } -#[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))] +#[cfg(all(unix, + not(target_os = "ios"), + not(target_os = "openbsd"), + not(target_os = "freebsd")))] mod imp { use self::OsRngInner::*; use super::{next_u32, next_u64}; @@ -282,3 +285,51 @@ mod imp { } } } + +#[cfg(target_os = "freebsd")] +mod imp { + use super::{next_u32, next_u64}; + + use io; + use libc; + use rand::Rng; + use ptr; + + 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 { + next_u32(&mut |v| self.fill_bytes(v)) + } + fn next_u64(&mut self) -> u64 { + next_u64(&mut |v| self.fill_bytes(v)) + } + fn fill_bytes(&mut self, v: &mut [u8]) { + let mib = [libc::CTL_KERN, libc::KERN_ARND]; + // kern.arandom permits a maximum buffer size of 256 bytes + 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) + }; + if ret == -1 || s_len != s.len() { + panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})", + ret, s.len(), s_len); + } + } + } + } +}