Skip to content

Commit

Permalink
Improve robustness of the Hermit backend and sys_fill_exact
Browse files Browse the repository at this point in the history
  • Loading branch information
newpavlov committed Nov 8, 2023
1 parent 169944f commit dd9dc6a
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 19 deletions.
2 changes: 2 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ impl Error {
pub const UNSUPPORTED: Error = internal_error(0);
/// The platform-specific `errno` returned a non-positive value.
pub const ERRNO_NOT_POSITIVE: Error = internal_error(1);
/// Encountered an unexpected situation which should not happen in practice.
pub const UNEXPECTED: Error = internal_error(2);
/// Call to iOS [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes) failed.
pub const IOS_SEC_RANDOM: Error = internal_error(3);
/// Call to Windows [`RtlGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom) failed.
Expand Down
21 changes: 13 additions & 8 deletions src/hermit.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::Error;
use core::{cmp::min, mem::MaybeUninit, num::NonZeroU32};
use core::{convert::TryInto, mem::MaybeUninit, num::NonZeroU32};

extern "C" {
fn sys_read_entropy(buffer: *mut u8, length: usize, flags: u32) -> isize;
Expand All @@ -8,14 +8,19 @@ extern "C" {
pub fn getrandom_inner(mut dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
while !dest.is_empty() {
let res = unsafe { sys_read_entropy(dest.as_mut_ptr() as *mut u8, dest.len(), 0) };
if res < 0 {
// SAFETY: all Hermit error codes use i32 under the hood:
// https://github.com/hermitcore/libhermit-rs/blob/master/src/errno.rs
let code = unsafe { NonZeroU32::new_unchecked((-res) as u32) };
return Err(code.into());
if res > 0 {
dest = dest.get_mut(res as usize..).ok_or(Error::UNEXPECTED)?;
} else {
// We should not get `res` equal to zero or smaller than `-i32::MAX`.
// If we get such unexpected value after all, we will return `Error::UNEXPECTED`.
let err = (-res)
.try_into()
.ok()
.and_then(NonZeroU32::new)
.map(Into::into)
.unwrap_or(Error::UNEXPECTED);
return Err(err);
}
let len = min(res as usize, dest.len());
dest = &mut dest[len..];
}
Ok(())
}
22 changes: 11 additions & 11 deletions src/util_libc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#![allow(dead_code)]
use crate::Error;
use core::{
cmp::min,
mem::MaybeUninit,
num::NonZeroU32,
ptr::NonNull,
Expand Down Expand Up @@ -68,19 +67,20 @@ pub fn sys_fill_exact(
mut buf: &mut [MaybeUninit<u8>],
sys_fill: impl Fn(&mut [MaybeUninit<u8>]) -> libc::ssize_t,
) -> Result<(), Error> {
use core::cmp::Ordering::*;

while !buf.is_empty() {
let res = sys_fill(buf);
if res < 0 {
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);
match res.cmp(&0) {
Greater => buf = buf.get_mut(res as usize..).ok_or(Error::UNEXPECTED)?,
Less => {
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);
}
}
} else {
// We don't check for EOF (ret = 0) as the data we are reading
// should be an infinite stream of random bytes.
let len = min(res as usize, buf.len());
buf = &mut buf[len..];
Equal => return Err(Error::UNEXPECTED),
}
}
Ok(())
Expand Down

0 comments on commit dd9dc6a

Please sign in to comment.