Merge pull request #9 from jasonbking/illumos
8 Update Solaris getrandom
This commit is contained in:
commit
7f68c78868
@ -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",
|
||||
|
@ -1,99 +0,0 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, 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<Option<RngSource>> = 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)
|
||||
}
|
99
src/solarish.rs
Normal file
99
src/solarish.rs
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, 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<Option<RngSource>> = 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<GetRandomFn> {
|
||||
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::<usize, Option<GetRandomFn>>(ptr) }
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user