From 9858ff3d92e0da8ae7e22d44ad8fe8284b3f92e0 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Thu, 6 Jun 2024 10:24:12 -0700 Subject: [PATCH] util_unix: Move dependency on libc's `errno` to callers. Make progress on reoving the libc dependency from util_unix, so we can remove the libc dependency for x86_64-unknown-linux-none. --- src/getrandom.rs | 5 +++-- src/linux_android.rs | 12 ++++++++---- src/linux_android_with_fallback.rs | 22 +++++++++------------- src/netbsd.rs | 11 ++++++----- src/use_file.rs | 9 +++++++-- src/util_unix.rs | 18 ++++++++---------- 6 files changed, 41 insertions(+), 36 deletions(-) diff --git a/src/getrandom.rs b/src/getrandom.rs index 743e5477..5b66e568 100644 --- a/src/getrandom.rs +++ b/src/getrandom.rs @@ -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_libc::last_os_error, util_unix::sys_fill_exact, Error}; use core::{ffi::c_void, mem::MaybeUninit}; pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { sys_fill_exact(dest, |buf| unsafe { - libc::getrandom(buf.as_mut_ptr().cast::(), buf.len(), 0) + let ret: isize = libc::getrandom(buf.as_mut_ptr().cast::(), buf.len(), 0); + usize::try_from(ret).map_err(|_| last_os_error()) }) } diff --git a/src/linux_android.rs b/src/linux_android.rs index 90b2edf3..151f7c5c 100644 --- a/src/linux_android.rs +++ b/src/linux_android.rs @@ -7,13 +7,17 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { } // Also used by linux_android_with_fallback to check if the syscall is available. -pub fn getrandom_syscall(buf: &mut [MaybeUninit]) -> libc::ssize_t { - unsafe { +pub fn getrandom_syscall(buf: &mut [MaybeUninit]) -> Result { + use crate::util_libc::last_os_error; + + let ret: libc::c_long = unsafe { libc::syscall( libc::SYS_getrandom, buf.as_mut_ptr().cast::(), buf.len(), 0, - ) as libc::ssize_t - } + ) + }; + const _: () = assert!(core::mem::size_of::() == core::mem::size_of::()); + usize::try_from(ret as isize).map_err(|_| last_os_error()) } diff --git a/src/linux_android_with_fallback.rs b/src/linux_android_with_fallback.rs index 98fa15e8..3a7d1bad 100644 --- a/src/linux_android_with_fallback.rs +++ b/src/linux_android_with_fallback.rs @@ -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]) -> Result<(), Error> { @@ -13,17 +13,13 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> 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, } } diff --git a/src/netbsd.rs b/src/netbsd.rs index 991e095b..8f71ab97 100644 --- a/src/netbsd.rs +++ b/src/netbsd.rs @@ -1,8 +1,8 @@ //! Implementation for NetBSD -use crate::{lazy::LazyPtr, util_unix::sys_fill_exact, Error}; +use crate::{lazy::LazyPtr, util_libc::last_os_error, util_unix::sys_fill_exact, Error}; use core::{ffi::c_void, mem::MaybeUninit, ptr}; -fn kern_arnd(buf: &mut [MaybeUninit]) -> libc::ssize_t { +fn kern_arnd(buf: &mut [MaybeUninit]) -> Result { static MIB: [libc::c_int; 2] = [libc::CTL_KERN, libc::KERN_ARND]; let mut len = buf.len(); let ret = unsafe { @@ -16,9 +16,9 @@ fn kern_arnd(buf: &mut [MaybeUninit]) -> libc::ssize_t { ) }; if ret == -1 { - -1 + Err(last_os_error()) } else { - len as libc::ssize_t + Ok(len) } } @@ -38,7 +38,8 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> 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::(), buf.len(), 0) + let ret: isize = func(buf.as_mut_ptr().cast::(), buf.len(), 0); + usize::try_from(ret as isize).map_err(|_| last_os_error()) }); } diff --git a/src/use_file.rs b/src/use_file.rs index 0ce276ab..dae3c790 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -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, @@ -22,7 +26,8 @@ const FD_UNINIT: usize = usize::max_value(); pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let fd = get_rng_fd()?; sys_fill_exact(dest, |buf| unsafe { - libc::read(fd, buf.as_mut_ptr().cast::(), buf.len()) + let ret: isize = libc::read(fd, buf.as_mut_ptr().cast::(), buf.len()); + usize::try_from(ret).map_err(|_| last_os_error()) }) } diff --git a/src/util_unix.rs b/src/util_unix.rs index d6e7baea..67513507 100644 --- a/src/util_unix.rs +++ b/src/util_unix.rs @@ -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], - sys_fill: impl Fn(&mut [MaybeUninit]) -> libc::ssize_t, + sys_fill: impl Fn(&mut [MaybeUninit]) -> Result, ) -> 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);