Skip to content

Commit

Permalink
util_unix: Move dependency on libc's errno to callers.
Browse files Browse the repository at this point in the history
Make progress on reoving the libc dependency from util_unix, so we
can remove the libc dependency for x86_64-unknown-linux-none.
  • Loading branch information
briansmith committed Jun 6, 2024
1 parent 778d4d9 commit 5887ed6
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 35 deletions.
5 changes: 3 additions & 2 deletions src/getrandom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@
//! 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::{util_unix::sys_fill_exact, Error};
use crate::{util_ibc::last_os_error, util_unix::sys_fill_exact, Error};
use core::{ffi::c_void, mem::MaybeUninit};

pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
sys_fill_exact(dest, |buf| unsafe {
libc::getrandom(buf.as_mut_ptr().cast::<c_void>(), buf.len(), 0)
let ret: isize = libc::getrandom(buf.as_mut_ptr().cast::<c_void>(), buf.len(), 0);
usize::try_from(ret).map_err(|_| last_os_error())
})
}
12 changes: 8 additions & 4 deletions src/linux_android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
}

// Also used by linux_android_with_fallback to check if the syscall is available.
pub fn getrandom_syscall(buf: &mut [MaybeUninit<u8>]) -> libc::ssize_t {
unsafe {
pub fn getrandom_syscall(buf: &mut [MaybeUninit<u8>]) -> Result<usize, Error> {
use crate::util_libc::last_os_error;

let ret: libc::c_long = unsafe {
libc::syscall(
libc::SYS_getrandom,
buf.as_mut_ptr().cast::<core::ffi::c_void>(),
buf.len(),
0,
) as libc::ssize_t
}
)
};
const _: () = assert!(core::mem::size_of::<libc::c_long>() == core::mem::size_of::<isize>());
usize::try_from(ret as isize).map_err(|_| last_os_error())
}
22 changes: 9 additions & 13 deletions src/linux_android_with_fallback.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Implementation for Linux / Android with `/dev/urandom` fallback
use crate::{lazy::LazyBool, linux_android, use_file, util_libc::last_os_error, Error};
use crate::{lazy::LazyBool, linux_android, use_file, Error};
use core::mem::MaybeUninit;

pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
Expand All @@ -13,17 +13,13 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
}

fn is_getrandom_available() -> bool {
if linux_android::getrandom_syscall(&mut []) < 0 {
match last_os_error().raw_os_error() {
Some(libc::ENOSYS) => false, // 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) => false, // Blocked by seccomp
_ => true,
}
} else {
true
match linux_android::getrandom_syscall(&mut []) {
Err(err) if err.raw_os_error() == Some(libc::ENOSYS) => false, // 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")]
Err(err) if err.raw_os_error() == Some(libc::EPERM) => false, // Blocked by seccomp
_ => true,
}
}
9 changes: 5 additions & 4 deletions src/netbsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use crate::{lazy::LazyPtr, util_unix::sys_fill_exact, Error};
use core::{ffi::c_void, mem::MaybeUninit, ptr};

fn kern_arnd(buf: &mut [MaybeUninit<u8>]) -> libc::ssize_t {
fn kern_arnd(buf: &mut [MaybeUninit<u8>]) -> Result<usize, Error> {
static MIB: [libc::c_int; 2] = [libc::CTL_KERN, libc::KERN_ARND];
let mut len = buf.len();
let ret = unsafe {
Expand All @@ -16,9 +16,9 @@ fn kern_arnd(buf: &mut [MaybeUninit<u8>]) -> libc::ssize_t {
)
};
if ret == -1 {
-1
Err(last_os_error())
} else {
len as libc::ssize_t
Ok(len)
}
}

Expand All @@ -38,7 +38,8 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
if !fptr.is_null() {
let func: GetRandomFn = unsafe { core::mem::transmute(fptr) };
return sys_fill_exact(dest, |buf| unsafe {
func(buf.as_mut_ptr().cast::<u8>(), buf.len(), 0)
let ret: isize = func(buf.as_mut_ptr().cast::<u8>(), buf.len(), 0);
usize::try_from(ret as isize).map_err(|_| last_os_error())
});
}

Expand Down
9 changes: 7 additions & 2 deletions src/use_file.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
//! Implementations that just need to read from a file
use crate::{util_libc::open_readonly, util_unix::sys_fill_exact, Error};
use crate::{
util_libc::{last_os_error, open_readonly},
util_unix::sys_fill_exact,
Error,
};
use core::{
cell::UnsafeCell,
ffi::c_void,
Expand All @@ -22,7 +26,8 @@ const FD_UNINIT: usize = usize::max_value();
pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
let fd = get_rng_fd()?;
sys_fill_exact(dest, |buf| unsafe {
libc::read(fd, buf.as_mut_ptr().cast::<c_void>(), buf.len())
let ret: isize = libc::read(fd, buf.as_mut_ptr().cast::<c_void>(), buf.len());
usize::try_from(ret).map_err(|_| last_os_error())
})
}

Expand Down
18 changes: 8 additions & 10 deletions src/util_unix.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
#![allow(dead_code)]
use crate::{util_libc::last_os_error, Error};
use crate::Error;
use core::mem::MaybeUninit;

// Fill a buffer by repeatedly invoking a system call. The `sys_fill` function:
// - should return -1 and set errno on failure
// - should return the number of bytes written on success
// Fill a buffer by repeatedly invoking a system call. The `sys_fill` function
// must return `Ok(written)` where `written` is the number of bytes written,
// or otherwise an error.
pub fn sys_fill_exact(
mut buf: &mut [MaybeUninit<u8>],
sys_fill: impl Fn(&mut [MaybeUninit<u8>]) -> libc::ssize_t,
sys_fill: impl Fn(&mut [MaybeUninit<u8>]) -> Result<usize, Error>,
) -> Result<(), Error> {
while !buf.is_empty() {
let res = sys_fill(buf);
match res {
res if res > 0 => buf = buf.get_mut(res as usize..).ok_or(Error::UNEXPECTED)?,
-1 => {
let err = last_os_error();
match sys_fill(buf) {
Ok(res) if res > 0 => buf = buf.get_mut(res..).ok_or(Error::UNEXPECTED)?,
Err(err) => {
// We should try again if the call was interrupted.
if err.raw_os_error() != Some(libc::EINTR) {
return Err(err);
Expand Down

0 comments on commit 5887ed6

Please sign in to comment.