Skip to content

Potential undefined behavior in hermit implementation. #377

Closed
@briansmith

Description

@briansmith

extern "C" {
fn sys_read_entropy(buffer: *mut u8, length: usize, flags: u32) -> isize;
}

getrandom/src/hermit.rs

Lines 9 to 16 in 35808a4

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 == -sizie::MIN then (-res) will overflow. To fix, use checked_neg().
  • if res < (i32::MIN as isize) then (-res) as u32 is a truncating, i.e. lossy conversion. To fix: avoid using as for integer conversions and instead use TryInto for this conversion.
  • if (-res) % 0x1_0000_0000 == 0 then (-res) as u32 is zero and then NonZeroU32::new_unchecked((-res) as u32) is undefined behavior. To fix, use the safe NonZerou32::new() instead.

Maybe somewhere hermit guarantees errors codes will never be this large but better to avoid the issue completely.

Something like:

     let code = res.checked_neg().map(u32::try_from).map(NonZeroU32::new).unwrap_or(something);

There would be no undefined behavior in the new version.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions