Skip to content

Potential undefined behavior in hermit implementation. #377

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.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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