Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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)
})
}
}
8 changes: 6 additions & 2 deletions src/backends/linux_raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ 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 +150,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
13 changes: 13 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,19 @@ 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 positive error code.
#[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 instance of an `Error` from a negative error code.
#[cfg(not(target_os = "uefi"))]
#[allow(dead_code)]
Expand Down
Loading
Loading