Skip to content

Commit 1705a6c

Browse files
committed
Improve robustness of the Hermit backend and sys_fill_exact
1 parent 169944f commit 1705a6c

3 files changed

Lines changed: 26 additions & 18 deletions

File tree

src/error.rs

Lines changed: 2 additions & 0 deletions
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.

src/hermit.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::Error;
2-
use core::{cmp::min, mem::MaybeUninit, num::NonZeroU32};
2+
use core::{convert::TryInto, mem::MaybeUninit, num::NonZeroU32};
33

44
extern "C" {
55
fn sys_read_entropy(buffer: *mut u8, length: usize, flags: u32) -> isize;
@@ -8,14 +8,19 @@ extern "C" {
88
pub fn getrandom_inner(mut dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
99
while !dest.is_empty() {
1010
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());
11+
if res > 0 {
12+
dest = dest.get_mut(res as usize..).ok_or(Error::UNEXPECTED)?;
13+
} else {
14+
// We should not get `res` equal to zero or smaller than `-i32::MAX`.
15+
// If we get such unexpected value after all, we will return `Error::UNEXPECTED`.
16+
let err = res
17+
.checked_neg()
18+
.and_then(|val| val.try_into().ok())
19+
.and_then(NonZeroU32::new)
20+
.map(Into::into)
21+
.unwrap_or(Error::UNEXPECTED);
22+
return Err(err);
1623
}
17-
let len = min(res as usize, dest.len());
18-
dest = &mut dest[len..];
1924
}
2025
Ok(())
2126
}

src/util_libc.rs

Lines changed: 11 additions & 10 deletions
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)