Skip to content

Commit e992e45

Browse files
josephlrnewpavlov
authored andcommitted
macOS: Try getentropy() then fallback to /dev/random (#46)
1 parent 5b56734 commit e992e45

File tree

4 files changed

+73
-19
lines changed

4 files changed

+73
-19
lines changed

src/ios.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2018 Developers of the Rand project.
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
9+
//! Implementation for iOS
10+
extern crate std;
11+
12+
use crate::Error;
13+
use core::num::NonZeroU32;
14+
use std::io;
15+
16+
// TODO: Make extern once extern_types feature is stabilized. See:
17+
// https://github.com/rust-lang/rust/issues/43467
18+
#[repr(C)]
19+
struct SecRandom([u8; 0]);
20+
21+
#[link(name = "Security", kind = "framework")]
22+
extern "C" {
23+
static kSecRandomDefault: *const SecRandom;
24+
25+
fn SecRandomCopyBytes(rnd: *const SecRandom, count: usize, bytes: *mut u8) -> i32;
26+
}
27+
28+
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
29+
let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, dest.len(), dest.as_mut_ptr()) };
30+
if ret == -1 {
31+
error!("SecRandomCopyBytes call failed");
32+
Err(io::Error::last_os_error().into())
33+
} else {
34+
Ok(())
35+
}
36+
}
37+
38+
#[inline(always)]
39+
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
40+
None
41+
}

src/lib.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
//! |------------------|---------------------------------------------------------
1515
//! | Linux, Android | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after reading from `/dev/random` once
1616
//! | Windows | [`RtlGenRandom`][3]
17-
//! | macOS, iOS | [`SecRandomCopyBytes`][4]
17+
//! | macOS | [`getentropy()`][19] if available, otherise [`/dev/random`][20] (identical to `/dev/urandom`)
18+
//! | iOS | [`SecRandomCopyBytes`][4]
1819
//! | FreeBSD | [`kern.arandom`][5]
1920
//! | OpenBSD, Bitrig | [`getentropy`][6]
2021
//! | NetBSD | [`/dev/urandom`][7] after reading from `/dev/random` once
@@ -115,6 +116,8 @@
115116
//! [16]: #support-for-webassembly-and-amsjs
116117
//! [17]: https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-api.md#__wasi_random_get
117118
//! [18]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
119+
//! [19]: https://www.unix.com/man-page/mojave/2/getentropy/
120+
//! [20]: https://www.unix.com/man-page/mojave/4/random/
118121
119122
#![doc(
120123
html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
@@ -167,6 +170,7 @@ mod error_impls;
167170
#[cfg(any(
168171
target_os = "android",
169172
target_os = "linux",
173+
target_os = "macos",
170174
target_os = "solaris",
171175
target_os = "illumos",
172176
))]
@@ -181,7 +185,7 @@ mod_use!(cfg(target_os = "freebsd"), freebsd);
181185
mod_use!(cfg(target_os = "fuchsia"), fuchsia);
182186
mod_use!(cfg(target_os = "haiku"), use_file);
183187
mod_use!(cfg(target_os = "illumos"), solaris_illumos);
184-
mod_use!(cfg(target_os = "ios"), macos);
188+
mod_use!(cfg(target_os = "ios"), ios);
185189
mod_use!(cfg(target_os = "linux"), linux_android);
186190
mod_use!(cfg(target_os = "macos"), macos);
187191
mod_use!(cfg(target_os = "netbsd"), use_file);

src/macos.rs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,45 @@
1-
// Copyright 2018 Developers of the Rand project.
1+
// Copyright 2019 Developers of the Rand project.
22
//
33
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
44
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
55
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88

9-
//! Implementation for MacOS / iOS
9+
//! Implementation for macOS
1010
extern crate std;
1111

12-
use crate::Error;
12+
use crate::{use_file, Error};
13+
use core::mem;
1314
use core::num::NonZeroU32;
15+
use lazy_static::lazy_static;
1416
use std::io;
1517

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

21-
#[link(name = "Security", kind = "framework")]
22-
extern "C" {
23-
static kSecRandomDefault: *const SecRandom;
24-
25-
fn SecRandomCopyBytes(rnd: *const SecRandom, count: usize, bytes: *mut u8) -> i32;
20+
fn fetch_getentropy() -> Option<GetEntropyFn> {
21+
let name = "getentropy\0";
22+
let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) };
23+
unsafe { mem::transmute(addr) }
2624
}
2725

2826
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
29-
let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, dest.len(), dest.as_mut_ptr()) };
30-
if ret == -1 {
31-
error!("SecRandomCopyBytes call failed");
32-
Err(io::Error::last_os_error().into())
33-
} else {
27+
lazy_static! {
28+
static ref GETENTROPY_FUNC: Option<GetEntropyFn> = fetch_getentropy();
29+
}
30+
if let Some(fptr) = *GETENTROPY_FUNC {
31+
for chunk in dest.chunks_mut(256) {
32+
let ret = unsafe { fptr(chunk.as_mut_ptr(), chunk.len()) };
33+
if ret != 0 {
34+
error!("getentropy syscall failed with ret={}", ret);
35+
return Err(io::Error::last_os_error().into());
36+
}
37+
}
3438
Ok(())
39+
} else {
40+
// We fallback to reading from /dev/random instead of SecRandomCopyBytes
41+
// to avoid high startup costs and linking the Security framework.
42+
use_file::getrandom_inner(dest)
3543
}
3644
}
3745

src/use_file.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const FILE_PATH: &str = "/dev/urandom";
2525
target_os = "dragonfly",
2626
target_os = "emscripten",
2727
target_os = "haiku",
28+
target_os = "macos",
2829
target_os = "solaris",
2930
target_os = "illumos"
3031
))]

0 commit comments

Comments
 (0)