Skip to content

Commit dd9dc6a

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

3 files changed

Lines changed: 26 additions & 19 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+
.try_into()
18+
.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 & 11 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,
@@ -68,19 +67,20 @@ pub fn sys_fill_exact(
6867
mut buf: &mut [MaybeUninit<u8>],
6968
sys_fill: impl Fn(&mut [MaybeUninit<u8>]) -> libc::ssize_t,
7069
) -> Result<(), Error> {
70+
use core::cmp::Ordering::*;
71+
7172
while !buf.is_empty() {
7273
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);
74+
match res.cmp(&0) {
75+
Greater => buf = buf.get_mut(res as usize..).ok_or(Error::UNEXPECTED)?,
76+
Less => {
77+
let err = last_os_error();
78+
// We should try again if the call was interrupted.
79+
if err.raw_os_error() != Some(libc::EINTR) {
80+
return Err(err);
81+
}
7882
}
79-
} else {
80-
// We don't check for EOF (ret = 0) as the data we are reading
81-
// should be an infinite stream of random bytes.
82-
let len = min(res as usize, buf.len());
83-
buf = &mut buf[len..];
83+
Equal => return Err(Error::UNEXPECTED),
8484
}
8585
}
8686
Ok(())

0 commit comments

Comments
 (0)