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
3 changes: 1 addition & 2 deletions src/backends/linux_android_with_fallback.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
//! Implementation for Linux / Android with `/dev/urandom` fallback
use super::{sanitizer, use_file};
use crate::Error;
use crate::{Error, util_libc};
use core::{
ffi::c_void,
mem::{MaybeUninit, transmute},
ptr::NonNull,
sync::atomic::{AtomicPtr, Ordering},
};
use use_file::util_libc;

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

Expand Down
5 changes: 1 addition & 4 deletions src/backends/netbsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! `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, util_libc};
use core::{
cmp,
ffi::c_void,
Expand All @@ -14,9 +14,6 @@ use core::{

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 Down
10 changes: 3 additions & 7 deletions src/backends/rdrand.rs
Original file line number Diff line number Diff line change
@@ -1,13 +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!");

cfg_if! {
if #[cfg(target_arch = "x86_64")] {
use core::arch::x86_64 as arch;
Expand All @@ -17,6 +11,8 @@ cfg_if! {
use core::arch::x86 as arch;
use arch::_rdrand32_step as rdrand_step;
type Word = u32;
} else {
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
5 changes: 5 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,13 @@ extern crate cfg_if;
use core::mem::MaybeUninit;

mod backends;
#[allow(dead_code, reason = "not used in all backends")]
mod error;
#[allow(dead_code, reason = "not used in all backends")]
mod lazy;
#[allow(dead_code, reason = "not used in all backends")]
mod util;
mod util_libc;

#[cfg(feature = "std")]
mod error_std_impls;
Expand Down
1 change: 0 additions & 1 deletion src/util.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#![allow(dead_code)]
use crate::Error;
use core::{mem::MaybeUninit, ptr, slice};

Expand Down
150 changes: 81 additions & 69 deletions src/util_libc.rs
Original file line number Diff line number Diff line change
@@ -1,81 +1,93 @@
use crate::Error;
use core::mem::MaybeUninit;
#[allow(unused_macros, reason = "not always used")]
macro_rules! emit_impl {
($get_errno:expr) => {
use crate::Error;
use core::mem::MaybeUninit;

cfg_if! {
if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "cygwin"))] {
use libc::__errno as errno_location;
} else if #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "hurd", target_os = "redox", target_os = "dragonfly"))] {
use libc::__errno_location as errno_location;
} else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] {
use libc::___errno as errno_location;
} else if #[cfg(any(target_os = "macos", target_os = "freebsd"))] {
use libc::__error as errno_location;
} else if #[cfg(target_os = "haiku")] {
use libc::_errnop as errno_location;
} else if #[cfg(target_os = "nto")] {
use libc::__get_errno_ptr as errno_location;
} else if #[cfg(any(all(target_os = "horizon", target_arch = "arm"), target_os = "vita"))] {
unsafe extern "C" {
// Not provided by libc: https://github.com/rust-lang/libc/issues/1995
fn __errno() -> *mut libc::c_int;
pub(crate) fn last_os_error() -> Error {
// We assume that on all targets which use the `util_libc` module `c_int` is equal to `i32`
let errno: i32 = unsafe { $get_errno };

if errno > 0 {
let code = errno
.checked_neg()
.expect("Positive number can be always negated");
Error::from_neg_error_code(code)
} else {
Error::ERRNO_NOT_POSITIVE
}
}
use __errno as errno_location;
} else if #[cfg(target_os = "aix")] {
use libc::_Errno as errno_location;
}
}

cfg_if! {
if #[cfg(target_os = "vxworks")] {
use libc::errnoGet as get_errno;
} else {
unsafe fn get_errno() -> libc::c_int { unsafe { *errno_location() }}
}
/// Fill a buffer by repeatedly invoking `sys_fill`.
///
/// The `sys_fill` function:
/// - should return -1 and set errno on failure
/// - should return the number of bytes written on success
#[allow(dead_code, reason = "not used in all backends")]
pub(crate) fn sys_fill_exact(
mut buf: &mut [MaybeUninit<u8>],
sys_fill: impl Fn(&mut [MaybeUninit<u8>]) -> libc::ssize_t,
) -> Result<(), Error> {
while !buf.is_empty() {
let res = sys_fill(buf);
match res {
res if res > 0 => {
let len = usize::try_from(res).map_err(|_| Error::UNEXPECTED)?;
buf = buf.get_mut(len..).ok_or(Error::UNEXPECTED)?;
}
-1 => {
let err = last_os_error();
// We should try again if the call was interrupted.
if err.raw_os_error() != Some(libc::EINTR) {
return Err(err);
}
}
// Negative return codes not equal to -1 should be impossible.
// EOF (ret = 0) should be impossible, as the data we are reading
// should be an infinite stream of random bytes.
_ => return Err(Error::UNEXPECTED),
}
}
Ok(())
}
};
}

pub(crate) fn last_os_error() -> Error {
// We assume that on all targets which use the `util_libc` module `c_int` is equal to `i32`
let errno: i32 = unsafe { get_errno() };

if errno > 0 {
let code = errno
.checked_neg()
.expect("Positive number can be always negated");
Error::from_neg_error_code(code)
} else {
Error::ERRNO_NOT_POSITIVE
}
#[allow(unused_macros, reason = "not always used")]
macro_rules! emit_impl_from_ptr {
($fn:path) => {
emit_impl!(*$fn());
};
}

/// Fill a buffer by repeatedly invoking `sys_fill`.
///
/// The `sys_fill` function:
/// - should return -1 and set errno on failure
/// - should return the number of bytes written on success
#[allow(dead_code)]
pub(crate) fn sys_fill_exact(
mut buf: &mut [MaybeUninit<u8>],
sys_fill: impl Fn(&mut [MaybeUninit<u8>]) -> libc::ssize_t,
) -> Result<(), Error> {
while !buf.is_empty() {
let res = sys_fill(buf);
match res {
res if res > 0 => {
let len = usize::try_from(res).map_err(|_| Error::UNEXPECTED)?;
buf = buf.get_mut(len..).ok_or(Error::UNEXPECTED)?;
}
-1 => {
let err = last_os_error();
// We should try again if the call was interrupted.
if err.raw_os_error() != Some(libc::EINTR) {
return Err(err);
cfg_if! {
if #[cfg(target_os = "vxworks")] {
emit_impl!(libc::errnoGet());
} else {
cfg_if! {
if #[cfg(any(all(target_os = "linux", target_env = ""), getrandom_backend = "custom", getrandom_backend = "linux_raw", getrandom_backend = "rdrand", getrandom_backend = "rndr"))] {
// No libc.
} else if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "cygwin"))] {
emit_impl_from_ptr!(libc::__errno);
} else if #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "hurd", target_os = "redox", target_os = "dragonfly"))] {
emit_impl_from_ptr!(libc::__errno_location);
} else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] {
emit_impl_from_ptr!(libc::___errno);
} else if #[cfg(any(target_os = "macos", target_os = "freebsd"))] {
emit_impl_from_ptr!(libc::__error);
} else if #[cfg(target_os = "haiku")] {
emit_impl_from_ptr!(libc::_errnop);
} else if #[cfg(target_os = "nto")] {
emit_impl_from_ptr!(libc::__get_errno_ptr);
} else if #[cfg(any(all(target_os = "horizon", target_arch = "arm"), target_os = "vita"))] {
unsafe extern "C" {
// Not provided by libc: https://github.com/rust-lang/libc/issues/1995
fn __errno() -> *mut libc::c_int;
}
emit_impl_from_ptr!(__errno);
} else if #[cfg(target_os = "aix")] {
emit_impl_from_ptr!(libc::_Errno);
}
// Negative return codes not equal to -1 should be impossible.
// EOF (ret = 0) should be impossible, as the data we are reading
// should be an infinite stream of random bytes.
_ => return Err(Error::UNEXPECTED),
}
}
Ok(())
}