From 7dbb95fbda6893c17bcf355f5b8e8a76896d93c6 Mon Sep 17 00:00:00 2001 From: Sven Van Asbroeck Date: Wed, 12 May 2021 13:09:34 -0400 Subject: [PATCH 1/3] rust/kernel: move from_kernel_result! macro to error.rs This macro is well-suited for use elsewhere in the Rust core. Move it out to a suitable place, error.rs. Signed-off-by: Sven Van Asbroeck --- rust/kernel/error.rs | 21 +++++++++++++++++++++ rust/kernel/file_operations.rs | 20 +------------------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 27043dc8778d75..66487fad686acc 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -6,6 +6,7 @@ use crate::{bindings, c_types}; use alloc::{alloc::AllocError, collections::TryReserveError}; +use core::convert::TryFrom; use core::{num::TryFromIntError, str::Utf8Error}; /// Generic integer kernel error. @@ -104,3 +105,23 @@ impl From for Error { Error::ENOMEM } } + +pub fn from_kernel_result_helper(r: Result) -> T +where + T: TryFrom, + T::Error: core::fmt::Debug, +{ + match r { + Ok(v) => v, + Err(e) => T::try_from(e.to_kernel_errno()).unwrap(), + } +} + +#[macro_export] +macro_rules! from_kernel_result { + ($($tt:tt)*) => {{ + $crate::error::from_kernel_result_helper((|| { + $($tt)* + })()) + }}; +} diff --git a/rust/kernel/file_operations.rs b/rust/kernel/file_operations.rs index cf59acbcd500ae..3c15bf387438aa 100644 --- a/rust/kernel/file_operations.rs +++ b/rust/kernel/file_operations.rs @@ -13,6 +13,7 @@ use crate::{ bindings, c_types, error::{Error, Result}, file::File, + from_kernel_result, io_buffer::{IoBufferReader, IoBufferWriter}, iov_iter::IovIter, sync::CondVar, @@ -78,25 +79,6 @@ pub enum SeekFrom { Current(i64), } -fn from_kernel_result(r: Result) -> T -where - T: TryFrom, - T::Error: core::fmt::Debug, -{ - match r { - Ok(v) => v, - Err(e) => T::try_from(e.to_kernel_errno()).unwrap(), - } -} - -macro_rules! from_kernel_result { - ($($tt:tt)*) => {{ - from_kernel_result((|| { - $($tt)* - })()) - }}; -} - unsafe extern "C" fn open_callback>( inode: *mut bindings::inode, file: *mut bindings::file, From 2ce3372a23cd976596504b55f161837a598749e2 Mon Sep 17 00:00:00 2001 From: Sven Van Asbroeck Date: Wed, 12 May 2021 16:12:48 -0400 Subject: [PATCH 2/3] rust/kernel: document from_kernel_result! macro This is required to pass the CI. Signed-off-by: Sven Van Asbroeck --- rust/kernel/error.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 66487fad686acc..be66cc395c6099 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -106,6 +106,7 @@ impl From for Error { } } +#[doc(hidden)] pub fn from_kernel_result_helper(r: Result) -> T where T: TryFrom, @@ -117,6 +118,27 @@ where } } +/// Transforms a [`crate::error::Result`] to a kernel C integer result. +/// +/// This is useful when calling Rust functions that return [`crate::error::Result`] +/// from inside `extern "C"` functions that need to return an integer +/// error result. +/// +/// `T` should be convertible to an integer via `TryFrom`. +/// +/// # Examples +/// +/// ```rust,no_run +/// unsafe extern "C" fn probe_callback( +/// pdev: *mut bindings::platform_device, +/// ) -> c_types::c_int { +/// from_kernel_result! { +/// let ptr = devm_alloc(pdev)?; +/// rust_helper_platform_set_drvdata(pdev, ptr); +/// Ok(0) +/// } +/// } +/// ``` #[macro_export] macro_rules! from_kernel_result { ($($tt:tt)*) => {{ From eb4c6e8f9a75e2a8061d5b47c6a72e6646c3e669 Mon Sep 17 00:00:00 2001 From: Sven Van Asbroeck Date: Wed, 12 May 2021 16:13:30 -0400 Subject: [PATCH 3/3] rust/kernel: improve from_kernel_result! macro safety `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 --- rust/kernel/error.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index be66cc395c6099..56f5855e975075 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -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. @@ -106,15 +106,20 @@ impl From 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(r: Result) -> T where - T: TryFrom, - T::Error: core::fmt::Debug, + T: From, { 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), } } @@ -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`. +/// `T` should be convertible to an `i16` via `From`. /// /// # Examples ///