From 819fb3fb382af9c4789c96995412b9e8390082dd Mon Sep 17 00:00:00 2001 From: Jason King Date: Sat, 23 Feb 2019 01:55:32 +0000 Subject: [PATCH] 8 Update Solaris getrandom --- src/lib.rs | 4 +- src/solaris.rs | 99 ------------------------------------------------- src/solarish.rs | 99 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 100 deletions(-) delete mode 100644 src/solaris.rs create mode 100644 src/solarish.rs diff --git a/src/lib.rs b/src/lib.rs index f60b8ae6..ccd0f49a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,6 +100,7 @@ target_os = "android", target_os = "netbsd", target_os = "solaris", + target_os = "illumos", target_os = "redox", target_os = "dragonfly", target_os = "haiku", @@ -138,7 +139,7 @@ mod_use!(cfg(target_os = "macos"), macos); mod_use!(cfg(target_os = "netbsd"), netbsd); mod_use!(cfg(target_os = "openbsd"), openbsd_bitrig); mod_use!(cfg(target_os = "redox"), redox); -mod_use!(cfg(target_os = "solaris"), solaris); +mod_use!(cfg(any(target_os = "solaris", target_os = "illumos")), solarish); mod_use!(cfg(windows), windows); mod_use!(cfg(target_env = "sgx"), sgx); @@ -171,6 +172,7 @@ mod_use!( target_os = "freebsd", target_os = "fuchsia", target_os = "haiku", + target_os = "illumos", target_os = "ios", target_os = "linux", target_os = "macos", diff --git a/src/solaris.rs b/src/solaris.rs deleted file mode 100644 index 742578a4..00000000 --- a/src/solaris.rs +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation for the Solaris family -//! -//! Read from `/dev/random`, with chunks of limited size (1040 bytes). -//! `/dev/random` uses the Hash_DRBG with SHA512 algorithm from NIST SP 800-90A. -//! `/dev/urandom` uses the FIPS 186-2 algorithm, which is considered less -//! secure. We choose to read from `/dev/random`. -//! -//! Since Solaris 11.3 the `getrandom` syscall is available. To make sure we can -//! compile on both Solaris and on OpenSolaris derivatives, that do not have the -//! function, we do a direct syscall instead of calling a library function. -//! -//! We have no way to differentiate between Solaris, illumos, SmartOS, etc. -extern crate libc; - -use super::Error; -use std::fs::File; -use std::io; -use std::io::Read; -use std::cell::RefCell; -use std::ops::DerefMut; - -enum RngSource { - GetRandom, - Device(File), -} - -thread_local!( - static RNG_SOURCE: RefCell> = RefCell::new(None); -); - -fn syscall_getrandom(dest: &mut [u8]) -> Result<(), Error> { - // repalce with libc? - const SYS_GETRANDOM: libc::c_long = 143; - - extern "C" { - fn syscall(number: libc::c_long, ...) -> libc::c_long; - } - - let ret = unsafe { - syscall(SYS_GETRANDOM, dest.as_mut_ptr(), dest.len(), 0) - }; - if ret == -1 || ret != dest.len() as i64 { - return Err(io::Error::last_os_error().into()); - } - Ok(()) -} - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - // The documentation says 1024 is the maximum for getrandom - // and 1040 for /dev/random. - RNG_SOURCE.with(|f| { - use_init(f, - || { - let s = if is_getrandom_available() { - RngSource::GetRandom - } else { - RngSource::Device(File::open("/dev/random")?) - }; - Ok(s) - }, |f| { - match f { - RngSource::GetRandom => for chunk in dest.chunks_mut(1024) { - syscall_getrandom(chunk) - }, - RngSource::Device(f) => for chunk in dest.chunks_mut(1040) { - f.read_exact(dest).map_err(From::from) - }, - } - }) - }) -} - -fn is_getrandom_available() -> bool { - use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; - use std::sync::{Once, ONCE_INIT}; - - static CHECKER: Once = ONCE_INIT; - static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT; - - CHECKER.call_once(|| { - let mut buf: [u8; 0] = []; - let available = match syscall_getrandom(&mut buf) { - Ok(()) => true, - Err(ref err) if err.raw_os_error() == Some(libc::ENOSYS) => false, - Err(_) => true, - }; - AVAILABLE.store(available, Ordering::Relaxed); - }); - - AVAILABLE.load(Ordering::Relaxed) -} diff --git a/src/solarish.rs b/src/solarish.rs new file mode 100644 index 00000000..8a84fd20 --- /dev/null +++ b/src/solarish.rs @@ -0,0 +1,99 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for the Solaris family +//! +//! Read from `/dev/random`, with chunks of limited size (256 bytes). +//! `/dev/random` uses the Hash_DRBG with SHA512 algorithm from NIST SP 800-90A. +//! `/dev/urandom` uses the FIPS 186-2 algorithm, which is considered less +//! secure. We choose to read from `/dev/random`. +//! +//! Since Solaris 11.3 and mid-2015 illumos, the `getrandom` syscall is available. +//! To make sure we can compile on both Solaris and its derivatives, as well as +//! function, we check for the existance of getrandom(2) in libc by calling +//! libc::dlsym. +extern crate libc; + +use super::Error; +use std::cell::RefCell; +use std::fs::File; +use std::io; +use std::io::Read; +use utils::use_init; + +#[cfg(target_os = "illumos")] +type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t; +#[cfg(target_os = "solaris")] +type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::c_int; + +enum RngSource { + GetRandom(GetRandomFn), + Device(File), +} + +thread_local!( + static RNG_SOURCE: RefCell> = RefCell::new(None); +); + +fn libc_getrandom(rand: GetRandomFn, dest: &mut [u8]) -> Result<(), Error> { + let ret = unsafe { rand(dest.as_mut_ptr(), dest.len(), 0) as libc::ssize_t }; + + if ret == -1 || ret != dest.len() as libc::ssize_t { + Err(io::Error::last_os_error().into()) + } else { + Ok(()) + } +} + +pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { + // 256 bytes is the lowest common denominator across all the Solaris + // derived platforms for atomically obtaining random data. + RNG_SOURCE.with(|f| { + use_init( + f, + || { + let s = match fetch_getrandom() { + Some(fptr) => RngSource::GetRandom(fptr), + None => RngSource::Device(File::open("/dev/random")?), + }; + Ok(s) + }, + |f| { + match f { + RngSource::GetRandom(rp) => { + for chunk in dest.chunks_mut(256) { + libc_getrandom(*rp, chunk)? + } + } + RngSource::Device(randf) => { + for chunk in dest.chunks_mut(256) { + randf.read_exact(chunk)? + } + } + }; + Ok(()) + }, + ) + }) +} + +fn fetch_getrandom() -> Option { + use std::mem; + use std::sync::atomic::{AtomicUsize, Ordering}; + + static FPTR: AtomicUsize = AtomicUsize::new(1); + + if FPTR.load(Ordering::SeqCst) == 1 { + let name = "getrandom\0"; + let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) as usize }; + FPTR.store(addr, Ordering::SeqCst); + } + + let ptr = FPTR.load(Ordering::SeqCst); + unsafe { mem::transmute::>(ptr) } +}