6.13-stable review patch. If anyone has any objections, please let me know. ------------------ From: Gary Guo <gary@xxxxxxxxxxx> commit 1bae8729e50a900f41e9a1c17ae81113e4cf62b8 upstream. The following FFI types are replaced compared to `core::ffi`: 1. `char` type is now always mapped to `u8`, since kernel uses `-funsigned-char` on the C code. `core::ffi` maps it to platform default ABI, which can be either signed or unsigned. 2. `long` is now always mapped to `isize`. It's very common in the kernel to use `long` to represent a pointer-sized integer, and in fact `intptr_t` is a typedef of `long` in the kernel. Enforce this mapping rather than mapping to `i32/i64` depending on platform can save us a lot of unnecessary casts. Signed-off-by: Gary Guo <gary@xxxxxxxxxxx> Reviewed-by: Alice Ryhl <aliceryhl@xxxxxxxxxx> Link: https://lore.kernel.org/r/20240913213041.395655-5-gary@xxxxxxxxxxx [ Moved `uaccess` changes from the next commit, since they were irrefutable patterns that Rust >= 1.82.0 warns about. Reworded slightly and reformatted a few documentation comments. Rebased on top of `rust-next`. Added the removal of two casts to avoid Clippy warnings. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@xxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- rust/ffi.rs | 37 ++++++++++++++++++++++++++++++++++++- rust/kernel/error.rs | 5 +---- rust/kernel/firmware.rs | 2 +- rust/kernel/miscdevice.rs | 4 ++-- rust/kernel/uaccess.rs | 27 +++++++-------------------- 5 files changed, 47 insertions(+), 28 deletions(-) --- a/rust/ffi.rs +++ b/rust/ffi.rs @@ -10,4 +10,39 @@ #![no_std] -pub use core::ffi::*; +macro_rules! alias { + ($($name:ident = $ty:ty;)*) => {$( + #[allow(non_camel_case_types, missing_docs)] + pub type $name = $ty; + + // Check size compatibility with `core`. + const _: () = assert!( + core::mem::size_of::<$name>() == core::mem::size_of::<core::ffi::$name>() + ); + )*} +} + +alias! { + // `core::ffi::c_char` is either `i8` or `u8` depending on architecture. In the kernel, we use + // `-funsigned-char` so it's always mapped to `u8`. + c_char = u8; + + c_schar = i8; + c_uchar = u8; + + c_short = i16; + c_ushort = u16; + + c_int = i32; + c_uint = u32; + + // In the kernel, `intptr_t` is defined to be `long` in all platforms, so we can map the type to + // `isize`. + c_long = isize; + c_ulong = usize; + + c_longlong = i64; + c_ulonglong = u64; +} + +pub use core::ffi::c_void; --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -153,11 +153,8 @@ impl Error { /// Returns the error encoded as a pointer. pub fn to_ptr<T>(self) -> *mut T { - #[cfg_attr(target_pointer_width = "32", allow(clippy::useless_conversion))] // SAFETY: `self.0` is a valid error due to its invariant. - unsafe { - bindings::ERR_PTR(self.0.get().into()) as *mut _ - } + unsafe { bindings::ERR_PTR(self.0.get() as _) as *mut _ } } /// Returns a string representing the error, if one exists. --- a/rust/kernel/firmware.rs +++ b/rust/kernel/firmware.rs @@ -12,7 +12,7 @@ use core::ptr::NonNull; /// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`, /// `bindings::firmware_request_platform`, `bindings::request_firmware_direct`. struct FwFunc( - unsafe extern "C" fn(*mut *const bindings::firmware, *const i8, *mut bindings::device) -> i32, + unsafe extern "C" fn(*mut *const bindings::firmware, *const u8, *mut bindings::device) -> i32, ); impl FwFunc { --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -225,7 +225,7 @@ unsafe extern "C" fn fops_ioctl<T: MiscD // SAFETY: Ioctl calls can borrow the private data of the file. let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; - match T::ioctl(device, cmd, arg as usize) { + match T::ioctl(device, cmd, arg) { Ok(ret) => ret as c_long, Err(err) => err.to_errno() as c_long, } @@ -245,7 +245,7 @@ unsafe extern "C" fn fops_compat_ioctl<T // SAFETY: Ioctl calls can borrow the private data of the file. let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; - match T::compat_ioctl(device, cmd, arg as usize) { + match T::compat_ioctl(device, cmd, arg) { Ok(ret) => ret as c_long, Err(err) => err.to_errno() as c_long, } --- a/rust/kernel/uaccess.rs +++ b/rust/kernel/uaccess.rs @@ -8,7 +8,7 @@ use crate::{ alloc::Flags, bindings, error::Result, - ffi::{c_ulong, c_void}, + ffi::c_void, prelude::*, transmute::{AsBytes, FromBytes}, }; @@ -224,13 +224,9 @@ impl UserSliceReader { if len > self.length { return Err(EFAULT); } - let Ok(len_ulong) = c_ulong::try_from(len) else { - return Err(EFAULT); - }; - // SAFETY: `out_ptr` points into a mutable slice of length `len_ulong`, so we may write + // SAFETY: `out_ptr` points into a mutable slice of length `len`, so we may write // that many bytes to it. - let res = - unsafe { bindings::copy_from_user(out_ptr, self.ptr as *const c_void, len_ulong) }; + let res = unsafe { bindings::copy_from_user(out_ptr, self.ptr as *const c_void, len) }; if res != 0 { return Err(EFAULT); } @@ -259,9 +255,6 @@ impl UserSliceReader { if len > self.length { return Err(EFAULT); } - let Ok(len_ulong) = c_ulong::try_from(len) else { - return Err(EFAULT); - }; let mut out: MaybeUninit<T> = MaybeUninit::uninit(); // SAFETY: The local variable `out` is valid for writing `size_of::<T>()` bytes. // @@ -272,7 +265,7 @@ impl UserSliceReader { bindings::_copy_from_user( out.as_mut_ptr().cast::<c_void>(), self.ptr as *const c_void, - len_ulong, + len, ) }; if res != 0 { @@ -335,12 +328,9 @@ impl UserSliceWriter { if len > self.length { return Err(EFAULT); } - let Ok(len_ulong) = c_ulong::try_from(len) else { - return Err(EFAULT); - }; - // SAFETY: `data_ptr` points into an immutable slice of length `len_ulong`, so we may read + // SAFETY: `data_ptr` points into an immutable slice of length `len`, so we may read // that many bytes from it. - let res = unsafe { bindings::copy_to_user(self.ptr as *mut c_void, data_ptr, len_ulong) }; + let res = unsafe { bindings::copy_to_user(self.ptr as *mut c_void, data_ptr, len) }; if res != 0 { return Err(EFAULT); } @@ -359,9 +349,6 @@ impl UserSliceWriter { if len > self.length { return Err(EFAULT); } - let Ok(len_ulong) = c_ulong::try_from(len) else { - return Err(EFAULT); - }; // SAFETY: The reference points to a value of type `T`, so it is valid for reading // `size_of::<T>()` bytes. // @@ -372,7 +359,7 @@ impl UserSliceWriter { bindings::_copy_to_user( self.ptr as *mut c_void, (value as *const T).cast::<c_void>(), - len_ulong, + len, ) }; if res != 0 {