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
6 changes: 0 additions & 6 deletions src/backends.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ cfg_if! {
pub use custom::*;
} else if #[cfg(getrandom_backend = "linux_getrandom")] {
mod getrandom;
mod sanitizer;
pub use getrandom::*;
} else if #[cfg(getrandom_backend = "linux_raw")] {
mod linux_raw;
mod sanitizer;
pub use linux_raw::*;
} else if #[cfg(getrandom_backend = "rdrand")] {
mod rdrand;
Expand Down Expand Up @@ -49,7 +47,6 @@ cfg_if! {
pub use unsupported::*;
} else if #[cfg(all(target_os = "linux", target_env = ""))] {
mod linux_raw;
mod sanitizer;
pub use linux_raw::*;
} else if #[cfg(target_os = "espidf")] {
mod esp_idf;
Expand Down Expand Up @@ -117,7 +114,6 @@ cfg_if! {
))] {
mod use_file;
mod linux_android_with_fallback;
mod sanitizer;
pub use linux_android_with_fallback::*;
} else if #[cfg(any(
target_os = "android",
Expand All @@ -132,8 +128,6 @@ cfg_if! {
all(target_os = "horizon", target_arch = "arm"),
))] {
mod getrandom;
#[cfg(any(target_os = "android", target_os = "linux"))]
mod sanitizer;
pub use getrandom::*;
} else if #[cfg(target_os = "solaris")] {
mod solaris;
Expand Down
7 changes: 4 additions & 3 deletions src/backends/getentropy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@ use core::{ffi::c_void, mem::MaybeUninit};

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

#[path = "../util_libc.rs"]
mod util_libc;
#[path = "../utils/get_errno.rs"]
mod utils;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could move imports of errno_location for 4 targets which use this backends here, but I don't think it's worth the trouble since all 4 targets use different names.


#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
for chunk in dest.chunks_mut(256) {
let ret = unsafe { libc::getentropy(chunk.as_mut_ptr().cast::<c_void>(), chunk.len()) };
if ret != 0 {
return Err(util_libc::last_os_error());
let errno = utils::get_errno();
return Err(Error::from_errno(errno));
}
}
Ok(())
Expand Down
15 changes: 4 additions & 11 deletions src/backends/getrandom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,12 @@ use core::mem::MaybeUninit;

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

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

#[inline]
pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
util_libc::sys_fill_exact(dest, |buf| {
let ret = unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) };

#[cfg(any(target_os = "android", target_os = "linux"))]
unsafe {
super::sanitizer::unpoison_linux_getrandom_result(buf, ret);
}

ret
utils::sys_fill_exact(dest, |buf| unsafe {
libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0)
})
}
16 changes: 7 additions & 9 deletions src/backends/linux_android_with_fallback.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
//! Implementation for Linux / Android with `/dev/urandom` fallback
use super::{sanitizer, use_file};
use super::use_file;
use crate::Error;
use core::{
ffi::c_void,
mem::{MaybeUninit, transmute},
ptr::NonNull,
sync::atomic::{AtomicPtr, Ordering},
};
use use_file::util_libc;
use use_file::utils;

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

Expand Down Expand Up @@ -44,13 +44,13 @@ fn init() -> NonNull<c_void> {
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
match utils::get_errno() {
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
libc::EPERM => NOT_AVAILABLE, // Blocked by seccomp
_ => fptr,
}
} else {
Expand Down Expand Up @@ -94,10 +94,8 @@ pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
} 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) };
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);
ret
utils::sys_fill_exact(dest, |buf| unsafe {
getrandom_fn(buf.as_mut_ptr().cast(), buf.len(), 0)
})
}
}
9 changes: 6 additions & 3 deletions src/backends/linux_raw.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
//! Implementation for Linux / Android using `asm!`-based syscalls.
use super::sanitizer;
pub use crate::util::{inner_u32, inner_u64};
use crate::{Error, MaybeUninit};

#[cfg(not(any(target_os = "android", target_os = "linux")))]
compile_error!("`linux_raw` backend can be enabled only for Linux/Android targets!");

#[path = "../utils/sanitizer.rs"]
mod utils;

#[allow(non_upper_case_globals)]
unsafe fn getrandom_syscall(buf: *mut u8, buflen: usize, flags: u32) -> isize {
let r0;
Expand Down Expand Up @@ -147,11 +149,12 @@ pub fn fill_inner(mut dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {

loop {
let ret = unsafe { getrandom_syscall(dest.as_mut_ptr().cast(), dest.len(), 0) };
unsafe { sanitizer::unpoison_linux_getrandom_result(dest, ret) };
match usize::try_from(ret) {
Ok(0) => return Err(Error::UNEXPECTED),
Ok(len) => {
dest = dest.get_mut(len..).ok_or(Error::UNEXPECTED)?;
let (l, r) = dest.split_at_mut_checked(len).ok_or(Error::UNEXPECTED)?;
unsafe { utils::unpoison(l) };
dest = r;
if dest.is_empty() {
return Ok(());
}
Expand Down
6 changes: 3 additions & 3 deletions src/backends/netbsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use core::{

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

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

unsafe extern "C" fn polyfill_using_kern_arand(
buf: *mut c_void,
Expand Down Expand Up @@ -72,7 +72,7 @@ pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
fptr = init();
}
let fptr = unsafe { mem::transmute::<*mut c_void, GetRandomFn>(fptr) };
util_libc::sys_fill_exact(dest, |buf| unsafe {
utils::sys_fill_exact(dest, |buf| unsafe {
fptr(buf.as_mut_ptr().cast::<c_void>(), buf.len(), 0)
})
}
2 changes: 1 addition & 1 deletion src/backends/rdrand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use crate::{Error, util::slice_as_uninit};
use core::mem::{MaybeUninit, size_of};

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

#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))]
Expand Down
2 changes: 1 addition & 1 deletion src/backends/rndr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ fn is_rndr_available() -> bool {

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

Expand Down
9 changes: 5 additions & 4 deletions src/backends/solaris.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@
//! which also explains why this crate should not use getentropy(2).
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};
use libc::___errno as errno_location;

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

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

const MAX_BYTES: usize = 1024;

#[inline]
Expand All @@ -33,7 +31,10 @@ pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
// Good. Keep going.
Ok(ret) if ret == chunk.len() => {}
// The syscall failed.
Ok(0) => return Err(util_libc::last_os_error()),
Ok(0) => {
let errno = unsafe { core::ptr::read(errno_location()) };
return Err(Error::from_errno(errno));
}
// All other cases should be impossible.
_ => return Err(Error::UNEXPECTED),
}
Expand Down
24 changes: 12 additions & 12 deletions src/backends/use_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ 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;
#[path = "../utils/sys_fill_exact.rs"]
pub(super) mod utils;

/// For all platforms, we use `/dev/urandom` rather than `/dev/random`.
/// For more information see the linked man pages in lib.rs.
Expand Down Expand Up @@ -46,7 +46,7 @@ pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
if fd == FD_UNINIT || fd == FD_ONGOING_INIT {
fd = open_or_wait()?;
}
util_libc::sys_fill_exact(dest, |buf| unsafe {
utils::sys_fill_exact(dest, |buf| unsafe {
libc::read(fd, buf.as_mut_ptr().cast::<c_void>(), buf.len())
})
}
Expand All @@ -58,10 +58,10 @@ fn open_readonly(path: &CStr) -> Result<libc::c_int, Error> {
if fd >= 0 {
return Ok(fd);
}
let err = util_libc::last_os_error();
let errno = utils::get_errno();
// We should try again if open() was interrupted.
if err.raw_os_error() != Some(libc::EINTR) {
return Err(err);
if errno != libc::EINTR {
return Err(Error::from_errno(errno));
}
}
}
Expand Down Expand Up @@ -136,7 +136,7 @@ mod sync {

#[cfg(any(target_os = "android", target_os = "linux"))]
mod sync {
use super::{Error, FD, FD_ONGOING_INIT, open_readonly, util_libc::last_os_error};
use super::{Error, FD, FD_ONGOING_INIT, open_readonly, utils};

/// Wait for atomic `FD` to change value from `FD_ONGOING_INIT` to something else.
///
Expand All @@ -152,7 +152,7 @@ mod sync {
debug_assert!({
match ret {
0 => true,
-1 => last_os_error().raw_os_error() == Some(libc::EAGAIN),
-1 => utils::get_errno() == libc::EAGAIN,
_ => false,
}
});
Expand Down Expand Up @@ -209,12 +209,12 @@ mod sync {
debug_assert_eq!(res, 1);
break Ok(());
}
let err = last_os_error();
let errno = utils::get_errno();
// Assuming that `poll` is called correctly,
// on Linux it can return only EINTR and ENOMEM errors.
match err.raw_os_error() {
Some(libc::EINTR) => continue,
_ => break Err(err),
match errno {
libc::EINTR => continue,
_ => break Err(Error::from_errno(errno)),
}
};
unsafe { libc::close(fd) };
Expand Down
6 changes: 2 additions & 4 deletions src/backends/vxworks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ use core::{
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 Expand Up @@ -42,7 +39,8 @@ pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
let p: *mut libc::c_uchar = chunk.as_mut_ptr().cast();
let ret = unsafe { libc::randABytes(p, chunk_len) };
if ret != 0 {
return Err(util_libc::last_os_error());
let errno = unsafe { libc::errnoGet() };
return Err(Error::from_errno(errno));
}
}
Ok(())
Expand Down
20 changes: 19 additions & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,25 @@ impl Error {
/// Custom errors can be in the range of 2^17..(2^17 + 2^16)
const CUSTOM_START: RawOsError = 1 << 17;

/// Creates a new instance of an `Error` from a negative error code.
/// Creates a new `Error` instance from a positive error code.
///
/// Returns [`Error::ERRNO_NOT_POSITIVE`] for zero and negative error codes.
#[cfg(not(target_os = "uefi"))]
#[allow(dead_code)]
pub(super) fn from_errno(errno: i32) -> Self {
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
}
}

/// Creates a new `Error` instance from a negative error code.
///
/// Returns [`Error::UNEXPECTED`] for zero and positive error codes.
#[cfg(not(target_os = "uefi"))]
#[allow(dead_code)]
pub(super) fn from_neg_error_code(code: RawOsError) -> Self {
Expand Down
Loading