Skip to content

Commit 7249e6e

Browse files
authored
Improve robustness of the Hermit backend and sys_fill_exact (#386)
1 parent 169944f commit 7249e6e

File tree

3 files changed

+29
-18
lines changed

3 files changed

+29
-18
lines changed

src/error.rs

+3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ impl Error {
3535
pub const UNSUPPORTED: Error = internal_error(0);
3636
/// The platform-specific `errno` returned a non-positive value.
3737
pub const ERRNO_NOT_POSITIVE: Error = internal_error(1);
38+
/// Encountered an unexpected situation which should not happen in practice.
39+
pub const UNEXPECTED: Error = internal_error(2);
3840
/// Call to iOS [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes) failed.
3941
pub const IOS_SEC_RANDOM: Error = internal_error(3);
4042
/// Call to Windows [`RtlGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom) failed.
@@ -164,6 +166,7 @@ fn internal_desc(error: Error) -> Option<&'static str> {
164166
match error {
165167
Error::UNSUPPORTED => Some("getrandom: this target is not supported"),
166168
Error::ERRNO_NOT_POSITIVE => Some("errno: did not return a positive value"),
169+
Error::UNEXPECTED => Some("unexpected situation"),
167170
Error::IOS_SEC_RANDOM => Some("SecRandomCopyBytes: iOS Security framework failure"),
168171
Error::WINDOWS_RTL_GEN_RANDOM => Some("RtlGenRandom: Windows system function failure"),
169172
Error::FAILED_RDRAND => Some("RDRAND: failed multiple times: CPU issue likely"),

src/hermit.rs

+15-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
use crate::Error;
2-
use core::{cmp::min, mem::MaybeUninit, num::NonZeroU32};
2+
use core::{mem::MaybeUninit, num::NonZeroU32};
3+
4+
/// Minimum return value which we should get from syscalls in practice,
5+
/// because Hermit uses positive `i32`s for error codes:
6+
/// https://github.com/hermitcore/libhermit-rs/blob/main/src/errno.rs
7+
const MIN_RET_CODE: isize = -(i32::MAX as isize);
38

49
extern "C" {
510
fn sys_read_entropy(buffer: *mut u8, length: usize, flags: u32) -> isize;
@@ -8,14 +13,16 @@ extern "C" {
813
pub fn getrandom_inner(mut dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
914
while !dest.is_empty() {
1015
let res = unsafe { sys_read_entropy(dest.as_mut_ptr() as *mut u8, dest.len(), 0) };
11-
if res < 0 {
12-
// SAFETY: all Hermit error codes use i32 under the hood:
13-
// https://github.com/hermitcore/libhermit-rs/blob/master/src/errno.rs
14-
let code = unsafe { NonZeroU32::new_unchecked((-res) as u32) };
15-
return Err(code.into());
16+
// Positive `isize`s can be safely casted to `usize`
17+
if res > 0 && (res as usize) <= dest.len() {
18+
dest = &mut dest[res as usize..];
19+
} else {
20+
let err = match res {
21+
MIN_RET_CODE..=-1 => NonZeroU32::new(-res as u32).unwrap().into(),
22+
_ => Error::UNEXPECTED,
23+
};
24+
return Err(err);
1625
}
17-
let len = min(res as usize, dest.len());
18-
dest = &mut dest[len..];
1926
}
2027
Ok(())
2128
}

src/util_libc.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#![allow(dead_code)]
99
use crate::Error;
1010
use core::{
11-
cmp::min,
1211
mem::MaybeUninit,
1312
num::NonZeroU32,
1413
ptr::NonNull,
@@ -70,17 +69,19 @@ pub fn sys_fill_exact(
7069
) -> Result<(), Error> {
7170
while !buf.is_empty() {
7271
let res = sys_fill(buf);
73-
if res < 0 {
74-
let err = last_os_error();
75-
// We should try again if the call was interrupted.
76-
if err.raw_os_error() != Some(libc::EINTR) {
77-
return Err(err);
72+
match res {
73+
res if res > 0 => buf = buf.get_mut(res as usize..).ok_or(Error::UNEXPECTED)?,
74+
-1 => {
75+
let err = last_os_error();
76+
// We should try again if the call was interrupted.
77+
if err.raw_os_error() != Some(libc::EINTR) {
78+
return Err(err);
79+
}
7880
}
79-
} else {
80-
// We don't check for EOF (ret = 0) as the data we are reading
81+
// Negative return codes not equal to -1 should be impossible.
82+
// EOF (ret = 0) should be impossible, as the data we are reading
8183
// should be an infinite stream of random bytes.
82-
let len = min(res as usize, buf.len());
83-
buf = &mut buf[len..];
84+
_ => return Err(Error::UNEXPECTED),
8485
}
8586
}
8687
Ok(())

0 commit comments

Comments
 (0)