Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macOS: Try getentropy() then fallback to /dev/random #46

Merged
merged 4 commits into from
Jun 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/ios.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// 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 iOS
extern crate std;

use crate::Error;
use core::num::NonZeroU32;
use std::io;

// TODO: Make extern once extern_types feature is stabilized. See:
// https://github.com/rust-lang/rust/issues/43467
#[repr(C)]
struct SecRandom([u8; 0]);

#[link(name = "Security", kind = "framework")]
extern "C" {
static kSecRandomDefault: *const SecRandom;

fn SecRandomCopyBytes(rnd: *const SecRandom, count: usize, bytes: *mut u8) -> i32;
}

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, dest.len(), dest.as_mut_ptr()) };
if ret == -1 {
error!("SecRandomCopyBytes call failed");
Err(io::Error::last_os_error().into())
} else {
Ok(())
}
}

#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
None
}
8 changes: 6 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
//! |------------------|---------------------------------------------------------
//! | Linux, Android | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after reading from `/dev/random` once
//! | Windows | [`RtlGenRandom`][3]
//! | macOS, iOS | [`SecRandomCopyBytes`][4]
//! | macOS | [`getentropy()`][19] if available, otherise [`/dev/random`][20] (identical to `/dev/urandom`)
//! | iOS | [`SecRandomCopyBytes`][4]
//! | FreeBSD | [`kern.arandom`][5]
//! | OpenBSD, Bitrig | [`getentropy`][6]
//! | NetBSD | [`/dev/urandom`][7] after reading from `/dev/random` once
Expand Down Expand Up @@ -115,6 +116,8 @@
//! [16]: #support-for-webassembly-and-amsjs
//! [17]: https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-api.md#__wasi_random_get
//! [18]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
//! [19]: https://www.unix.com/man-page/mojave/2/getentropy/
//! [20]: https://www.unix.com/man-page/mojave/4/random/

#![doc(
html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
Expand Down Expand Up @@ -167,6 +170,7 @@ mod error_impls;
#[cfg(any(
target_os = "android",
target_os = "linux",
target_os = "macos",
target_os = "solaris",
target_os = "illumos",
))]
Expand All @@ -181,7 +185,7 @@ mod_use!(cfg(target_os = "freebsd"), freebsd);
mod_use!(cfg(target_os = "fuchsia"), fuchsia);
mod_use!(cfg(target_os = "haiku"), use_file);
mod_use!(cfg(target_os = "illumos"), solaris_illumos);
mod_use!(cfg(target_os = "ios"), macos);
mod_use!(cfg(target_os = "ios"), ios);
mod_use!(cfg(target_os = "linux"), linux_android);
mod_use!(cfg(target_os = "macos"), macos);
mod_use!(cfg(target_os = "netbsd"), use_file);
Expand Down
42 changes: 25 additions & 17 deletions src/macos.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,45 @@
// Copyright 2018 Developers of the Rand project.
// Copyright 2019 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 MacOS / iOS
//! Implementation for macOS
extern crate std;

use crate::Error;
use crate::{use_file, Error};
use core::mem;
use core::num::NonZeroU32;
use lazy_static::lazy_static;
use std::io;

// TODO: Make extern once extern_types feature is stabilized. See:
// https://github.com/rust-lang/rust/issues/43467
#[repr(C)]
struct SecRandom([u8; 0]);
type GetEntropyFn = unsafe extern "C" fn(*mut u8, libc::size_t) -> libc::c_int;

#[link(name = "Security", kind = "framework")]
extern "C" {
static kSecRandomDefault: *const SecRandom;

fn SecRandomCopyBytes(rnd: *const SecRandom, count: usize, bytes: *mut u8) -> i32;
fn fetch_getentropy() -> Option<GetEntropyFn> {
let name = "getentropy\0";
let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) };
unsafe { mem::transmute(addr) }
}

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, dest.len(), dest.as_mut_ptr()) };
if ret == -1 {
error!("SecRandomCopyBytes call failed");
Err(io::Error::last_os_error().into())
} else {
lazy_static! {
static ref GETENTROPY_FUNC: Option<GetEntropyFn> = fetch_getentropy();
}
if let Some(fptr) = *GETENTROPY_FUNC {
for chunk in dest.chunks_mut(256) {
let ret = unsafe { fptr(chunk.as_mut_ptr(), chunk.len()) };
if ret != 0 {
error!("getentropy syscall failed with ret={}", ret);
return Err(io::Error::last_os_error().into());
}
}
Ok(())
} else {
// We fallback to reading from /dev/random instead of SecRandomCopyBytes
// to avoid high startup costs and linking the Security framework.
use_file::getrandom_inner(dest)
}
}

Expand Down
1 change: 1 addition & 0 deletions src/use_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const FILE_PATH: &str = "/dev/urandom";
target_os = "dragonfly",
target_os = "emscripten",
target_os = "haiku",
target_os = "macos",
target_os = "solaris",
target_os = "illumos"
))]
Expand Down