Skip to content

Commit

Permalink
rust/kernel: improve from_kernel_result! macro safety
Browse files Browse the repository at this point in the history
`from_kernel_result!` could panic if the return integer type (`T`) is
unable to hold the negative `errno`. Since `errno`s range from
`1` to `4095`, functions returning integer types unable to hold
values in the [-4095, -1] range could potentially panic.

This includes all unsigned integers, and signed integers with
insufficient bits, such as `c_char`.

Fix by making sure that the return integer type is always suitable
to hold the negative `errno`. Use the Rust type system to verify this
at build time.

Signed-off-by: Sven Van Asbroeck <[email protected]>
  • Loading branch information
Sven Van Asbroeck committed May 18, 2021
1 parent 2ce3372 commit eb4c6e8
Showing 1 changed file with 10 additions and 5 deletions.
15 changes: 10 additions & 5 deletions rust/kernel/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use crate::{bindings, c_types};
use alloc::{alloc::AllocError, collections::TryReserveError};
use core::convert::TryFrom;
use core::convert::From;
use core::{num::TryFromIntError, str::Utf8Error};

/// Generic integer kernel error.
Expand Down Expand Up @@ -106,15 +106,20 @@ impl From<AllocError> for Error {
}
}

// # Invariant: `-bindings::MAX_ERRNO` fits in an `i16`.
crate::static_assert!(bindings::MAX_ERRNO <= -(i16::MIN as i32) as u32);

#[doc(hidden)]
pub fn from_kernel_result_helper<T>(r: Result<T>) -> T
where
T: TryFrom<c_types::c_int>,
T::Error: core::fmt::Debug,
T: From<i16>,
{
match r {
Ok(v) => v,
Err(e) => T::try_from(e.to_kernel_errno()).unwrap(),
// NO-OVERFLOW: negative `errno`s are no smaller than `-bindings::MAX_ERRNO`,
// `-bindings::MAX_ERRNO` fits in an `i16` as per invariant above,
// therefore a negative `errno` always fits in an `i16` and will not overflow.
Err(e) => T::from(e.to_kernel_errno() as i16),
}
}

Expand All @@ -124,7 +129,7 @@ where
/// from inside `extern "C"` functions that need to return an integer
/// error result.
///
/// `T` should be convertible to an integer via `TryFrom<c_types::c_int>`.
/// `T` should be convertible to an `i16` via `From<i16>`.
///
/// # Examples
///
Expand Down

0 comments on commit eb4c6e8

Please sign in to comment.