Skip to content
Open
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
5 changes: 1 addition & 4 deletions src/backends/getentropy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@
//! - vita newlib since Dec 2021
//!
//! For these targets, we use getentropy(2) because getrandom(2) doesn't exist.
use crate::Error;
use crate::{Error, util_libc};
use core::{ffi::c_void, mem::MaybeUninit};

pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
mod util_libc;

#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
for chunk in dest.chunks_mut(256) {
Expand Down
5 changes: 1 addition & 4 deletions src/backends/getrandom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,11 @@
//! GRND_RANDOM is not recommended. On NetBSD/FreeBSD/Dragonfly/3ds, it does
//! nothing. On illumos, the default pool is used to implement getentropy(2),
//! so we assume it is acceptable here.
use crate::Error;
use crate::{Error, util_libc};
use core::mem::MaybeUninit;

pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
mod util_libc;

#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
util_libc::sys_fill_exact(dest, |buf| {
Expand Down
76 changes: 28 additions & 48 deletions src/backends/linux_android_with_fallback.rs
Original file line number Diff line number Diff line change
@@ -1,71 +1,60 @@
//! Implementation for Linux / Android with `/dev/urandom` fallback
use super::{sanitizer, use_file};
use crate::Error;
use crate::{Error, lazy, util_libc};
use core::{
ffi::c_void,
mem::{MaybeUninit, transmute},
ptr::NonNull,
sync::atomic::{AtomicPtr, Ordering},
ptr,
};
use use_file::util_libc;

pub use crate::util::{inner_u32, inner_u64};

type GetRandomFn = unsafe extern "C" fn(*mut c_void, libc::size_t, libc::c_uint) -> libc::ssize_t;

/// Sentinel value which indicates that `libc::getrandom` either not available,
/// or not supported by kernel.
const NOT_AVAILABLE: NonNull<c_void> = unsafe { NonNull::new_unchecked(usize::MAX as *mut c_void) };

static GETRANDOM_FN: AtomicPtr<c_void> = AtomicPtr::new(core::ptr::null_mut());
const NOT_AVAILABLE: *mut c_void = usize::MAX as *mut c_void;

#[cold]
#[inline(never)]
fn init() -> NonNull<c_void> {
fn init() -> *mut c_void {
// Use static linking to `libc::getrandom` on MUSL targets and `dlsym` everywhere else
#[cfg(not(target_env = "musl"))]
let raw_ptr = {
static NAME: &[u8] = b"getrandom\0";
let name_ptr = NAME.as_ptr().cast::<libc::c_char>();
unsafe { libc::dlsym(libc::RTLD_DEFAULT, name_ptr) }
};
let fptr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, c"getrandom".as_ptr()) };
#[cfg(target_env = "musl")]
let raw_ptr = {
let fptr = {
let fptr: GetRandomFn = libc::getrandom;
unsafe { transmute::<GetRandomFn, *mut c_void>(fptr) }
};

let res_ptr = match NonNull::new(raw_ptr) {
Some(fptr) => {
let getrandom_fn = unsafe { transmute::<NonNull<c_void>, GetRandomFn>(fptr) };
let dangling_ptr = NonNull::dangling().as_ptr();
// Check that `getrandom` syscall is supported by kernel
let res = unsafe { getrandom_fn(dangling_ptr, 0, 0) };
if cfg!(getrandom_test_linux_fallback) {
NOT_AVAILABLE
} else if res.is_negative() {
match util_libc::last_os_error().raw_os_error() {
Some(libc::ENOSYS) => NOT_AVAILABLE, // No kernel support
// The fallback on EPERM is intentionally not done on Android since this workaround
// seems to be needed only for specific Linux-based products that aren't based
// on Android. See https://github.com/rust-random/getrandom/issues/229.
#[cfg(target_os = "linux")]
Some(libc::EPERM) => NOT_AVAILABLE, // Blocked by seccomp
_ => fptr,
}
} else {
fptr
let res_ptr = if !fptr.is_null() {
let getrandom_fn = unsafe { transmute::<*mut c_void, GetRandomFn>(fptr) };
// Check that `getrandom` syscall is supported by kernel
let res = unsafe { getrandom_fn(ptr::dangling_mut(), 0, 0) };
if cfg!(getrandom_test_linux_fallback) {
NOT_AVAILABLE
} else if res.is_negative() {
match util_libc::last_os_error().raw_os_error() {
Some(libc::ENOSYS) => NOT_AVAILABLE, // No kernel support
// The fallback on EPERM is intentionally not done on Android since this workaround
// seems to be needed only for specific Linux-based products that aren't based
// on Android. See https://github.com/rust-random/getrandom/issues/229.
#[cfg(target_os = "linux")]
Some(libc::EPERM) => NOT_AVAILABLE, // Blocked by seccomp
_ => fptr,
}
} else {
fptr
}
None => NOT_AVAILABLE,
} else {
NOT_AVAILABLE
};

#[cfg(getrandom_test_linux_without_fallback)]
if res_ptr == NOT_AVAILABLE {
panic!("Fallback is triggered with enabled `getrandom_test_linux_without_fallback`")
}

GETRANDOM_FN.store(res_ptr.as_ptr(), Ordering::Release);
res_ptr
}

Expand All @@ -77,23 +66,14 @@ fn use_file_fallback(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {

#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
// Despite being only a single atomic variable, we still cannot always use
// Ordering::Relaxed, as we need to make sure a successful call to `init`
// is "ordered before" any data read through the returned pointer (which
// occurs when the function is called). Our implementation mirrors that of
// the one in libstd, meaning that the use of non-Relaxed operations is
// probably unnecessary.
let raw_ptr = GETRANDOM_FN.load(Ordering::Acquire);
let fptr = match NonNull::new(raw_ptr) {
Some(p) => p,
None => init(),
};
static GETRANDOM_FN: lazy::LazyPtr<c_void> = lazy::LazyPtr::new();
let fptr = GETRANDOM_FN.unsync_init(init);

if fptr == NOT_AVAILABLE {
use_file_fallback(dest)
} else {
// note: `transmute` is currently the only way to convert a pointer into a function reference
let getrandom_fn = unsafe { transmute::<NonNull<c_void>, GetRandomFn>(fptr) };
let getrandom_fn = unsafe { transmute::<*mut c_void, GetRandomFn>(fptr) };
util_libc::sys_fill_exact(dest, |buf| unsafe {
let ret = getrandom_fn(buf.as_mut_ptr().cast(), buf.len(), 0);
sanitizer::unpoison_linux_getrandom_result(buf, ret);
Expand Down
31 changes: 8 additions & 23 deletions src/backends/netbsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,16 @@
//! `getrandom(2)` was introduced in NetBSD 10. To support older versions we
//! implement our own weak linkage to it, and provide a fallback based on the
//! KERN_ARND sysctl.
use crate::Error;
use crate::{Error, lazy, util_libc};
use core::{
cmp,
ffi::c_void,
mem::{self, MaybeUninit},
ptr,
sync::atomic::{AtomicPtr, Ordering},
};

pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
mod util_libc;

unsafe extern "C" fn polyfill_using_kern_arand(
buf: *mut c_void,
buflen: libc::size_t,
Expand All @@ -42,35 +38,24 @@ unsafe extern "C" fn polyfill_using_kern_arand(

type GetRandomFn = unsafe extern "C" fn(*mut c_void, libc::size_t, libc::c_uint) -> libc::ssize_t;

static GETRANDOM: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());

#[cold]
#[inline(never)]
fn init() -> *mut c_void {
static NAME: &[u8] = b"getrandom\0";
let name_ptr = NAME.as_ptr().cast::<libc::c_char>();
let mut ptr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name_ptr) };
let ptr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, c"getrandom".as_ptr()) };
if ptr.is_null() || cfg!(getrandom_test_netbsd_fallback) {
// Verify `polyfill_using_kern_arand` has the right signature.
const POLYFILL: GetRandomFn = polyfill_using_kern_arand;
ptr = POLYFILL as *mut c_void;
POLYFILL as *mut c_void
} else {
ptr
}
GETRANDOM.store(ptr, Ordering::Release);
ptr
}

#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
// Despite being only a single atomic variable, we still cannot always use
// Ordering::Relaxed, as we need to make sure a successful call to `init`
// is "ordered before" any data read through the returned pointer (which
// occurs when the function is called). Our implementation mirrors that of
// the one in libstd, meaning that the use of non-Relaxed operations is
// probably unnecessary.
let mut fptr = GETRANDOM.load(Ordering::Acquire);
if fptr.is_null() {
fptr = init();
}
static GETRANDOM_FN: lazy::LazyPtr<c_void> = lazy::LazyPtr::new();

let fptr = GETRANDOM_FN.unsync_init(init);
let fptr = unsafe { mem::transmute::<*mut c_void, GetRandomFn>(fptr) };
util_libc::sys_fill_exact(dest, |buf| unsafe {
fptr(buf.as_mut_ptr().cast::<c_void>(), buf.len(), 0)
Expand Down
5 changes: 1 addition & 4 deletions src/backends/rdrand.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
//! RDRAND backend for x86(-64) targets
use crate::{Error, util::slice_as_uninit};
use crate::{Error, lazy, util::slice_as_uninit};
use core::mem::{MaybeUninit, size_of};

#[path = "../lazy.rs"]
mod lazy;

#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))]
compile_error!("`rdrand` backend can be enabled only for x86 and x86-64 targets!");

Expand Down
3 changes: 1 addition & 2 deletions src/backends/rndr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ fn is_rndr_available() -> bool {

#[cfg(not(target_feature = "rand"))]
fn is_rndr_available() -> bool {
#[path = "../lazy.rs"]
mod lazy;
use crate::lazy;
static RNDR_GOOD: lazy::LazyBool = lazy::LazyBool::new();

cfg_if::cfg_if! {
Expand Down
5 changes: 1 addition & 4 deletions src/backends/solaris.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,11 @@
//! For more information, see the man page linked in lib.rs and this blog post:
//! https://blogs.oracle.com/solaris/post/solaris-new-system-calls-getentropy2-and-getrandom2
//! which also explains why this crate should not use getentropy(2).
use crate::Error;
use crate::{Error, util_libc};
use core::{ffi::c_void, mem::MaybeUninit};

pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
mod util_libc;

const MAX_BYTES: usize = 1024;

#[inline]
Expand Down
5 changes: 1 addition & 4 deletions src/backends/use_file.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Implementations that just need to read from a file
use crate::Error;
use crate::{Error, util_libc};
use core::{
ffi::{CStr, c_void},
mem::MaybeUninit,
Expand All @@ -9,9 +9,6 @@ use core::{
#[cfg(not(any(target_os = "android", target_os = "linux")))]
pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
pub(super) mod util_libc;

/// For all platforms, we use `/dev/urandom` rather than `/dev/random`.
/// For more information see the linked man pages in lib.rs.
/// - On Linux, "/dev/urandom is preferred and sufficient in all use cases".
Expand Down
5 changes: 1 addition & 4 deletions src/backends/vxworks.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
//! Implementation for VxWorks
use crate::Error;
use crate::{Error, util_libc};
use core::{
cmp::Ordering::{Equal, Greater, Less},
mem::MaybeUninit,
sync::atomic::{AtomicBool, Ordering::Relaxed},
};

#[path = "../util_libc.rs"]
mod util_libc;

pub use crate::util::{inner_u32, inner_u64};

static RNG_INIT: AtomicBool = AtomicBool::new(false);
Expand Down
2 changes: 0 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ impl Error {

/// Creates a new instance of an `Error` from a negative error code.
#[cfg(not(target_os = "uefi"))]
#[allow(dead_code)]
pub(super) fn from_neg_error_code(code: RawOsError) -> Self {
if code < 0 {
let code = NonZeroRawOsError::new(code).expect("`code` is negative");
Expand All @@ -71,7 +70,6 @@ impl Error {

/// Creates a new instance of an `Error` from an UEFI error code.
#[cfg(target_os = "uefi")]
#[allow(dead_code)]
pub(super) fn from_uefi_code(code: RawOsError) -> Self {
if code & UEFI_ERROR_FLAG != 0 {
let code = NonZeroRawOsError::new(code).expect("The highest bit of `code` is set to 1");
Expand Down
Loading