6.18-stable review patch. If anyone has any objections, please let me know. ------------------ From: Sami Tolvanen commit 7d109178cd644268326cd31702ed46c7ac8bb300 upstream. bindgen generates bindings::dma_data_direction as an integer by default, while C callback tables such as dma_buf_ops declare the parameter as enum dma_data_direction. kCFI encodes enum types by name even with integer normalization, so the type ids would not match when C calls into a Rust callback taking bindings::dma_data_direction. Generate dma_data_direction as a newtype with a cfi_encoding, as is done for lru_status, and convert DataDirection through the newtype's constants. Signed-off-by: Sami Tolvanen Reviewed-by: Alice Ryhl Reviewed-by: Gary Guo Acked-by: Danilo Krummrich Cc: stable@vger.kernel.org Fixes: c2437c43cfb1 ("rust: dma: implement DataDirection") Link: https://patch.msgid.link/20261019-rust-cfi-fixes-v1-3-9503472ba738@google.com Signed-off-by: Miguel Ojeda [ Replaced bindgen's custom enum attribute option with sed post-processing to support older bindgen. - Miguel ] Signed-off-by: Miguel Ojeda Signed-off-by: Sasha Levin --- rust/Makefile | 1 + rust/bindgen_parameters | 1 + rust/kernel/dma.rs | 21 +++++++++++---------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/rust/Makefile b/rust/Makefile index 3f1abad648e66..d6429e68949fe 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -368,6 +368,7 @@ $(obj)/bindings/bindings_generated.rs: private bindgen_target_flags = \ $(shell grep -Ev '^#|^$$' $(src)/bindgen_parameters) $(obj)/bindings/bindings_generated.rs: private bindgen_target_extra = ; \ sed -Ei 's/pub const RUST_CONST_HELPER_([a-zA-Z0-9_]*)/pub const \1/g' $@; \ + sed -Ei 's/^pub struct dma_data_direction\(/#[cfi_encoding="18dma_data_direction"]\n&/' $@; \ sed -Ei 's/^pub struct hrtimer_restart\(/#[cfi_encoding="15hrtimer_restart"]\n&/' $@; \ sed -Ei 's/^pub struct irqreturn\(/#[cfi_encoding="9irqreturn"]\n&/' $@ $(obj)/bindings/bindings_generated.rs: $(src)/bindings/bindings_helper.h \ diff --git a/rust/bindgen_parameters b/rust/bindgen_parameters index 6f76fdcffd58d..a5d547dc8e8ea 100644 --- a/rust/bindgen_parameters +++ b/rust/bindgen_parameters @@ -24,6 +24,7 @@ --opaque-type spinlock # enums that appear in indirect function calls should specify a cfi type +--newtype-enum dma_data_direction --newtype-enum hrtimer_restart --newtype-enum irqreturn diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 4ce9e5d7f3dd0..b6c73db358ced 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -267,25 +267,25 @@ pub enum DataDirection { /// /// This is used when the buffer can be both read from and written to by the device. /// The cache for the corresponding memory region is both flushed and invalidated. - Bidirectional = Self::const_cast(bindings::dma_data_direction_DMA_BIDIRECTIONAL), + Bidirectional = Self::const_cast(bindings::dma_data_direction::DMA_BIDIRECTIONAL), /// The DMA mapping is for data transfer from memory to the device (write). /// /// The CPU has prepared data in the buffer, and the device will read it. /// The cache for the corresponding memory region is flushed before device access. - ToDevice = Self::const_cast(bindings::dma_data_direction_DMA_TO_DEVICE), + ToDevice = Self::const_cast(bindings::dma_data_direction::DMA_TO_DEVICE), /// The DMA mapping is for data transfer from the device to memory (read). /// /// The device will write data into the buffer for the CPU to read. /// The cache for the corresponding memory region is invalidated before CPU access. - FromDevice = Self::const_cast(bindings::dma_data_direction_DMA_FROM_DEVICE), + FromDevice = Self::const_cast(bindings::dma_data_direction::DMA_FROM_DEVICE), /// The DMA mapping is not for data transfer. /// /// This is primarily for debugging purposes. With this direction, the DMA mapping API /// will not perform any cache coherency operations. - None = Self::const_cast(bindings::dma_data_direction_DMA_NONE), + None = Self::const_cast(bindings::dma_data_direction::DMA_NONE), } impl DataDirection { @@ -297,7 +297,7 @@ const fn const_cast(val: bindings::dma_data_direction) -> u32 { // CAST: The C standard allows compilers to choose different integer types for enums. // To safely check the value, we cast it to a wide signed integer type (`i128`) // which can hold any standard C integer enum type without truncation. - let wide_val = val as i128; + let wide_val = val.0 as i128; // Check if the value is outside the valid range for the target type `u32`. // CAST: `u32::MAX` is cast to `i128` to match the type of `wide_val` for the comparison. @@ -315,11 +315,12 @@ const fn const_cast(val: bindings::dma_data_direction) -> u32 { impl From for bindings::dma_data_direction { /// Returns the raw representation of [`enum dma_data_direction`]. fn from(direction: DataDirection) -> Self { - // CAST: `direction as u32` gets the underlying representation of our `#[repr(u32)]` enum. - // The subsequent cast to `Self` (the bindgen type) assumes the C enum is compatible - // with the enum variants of `DataDirection`, which is a valid assumption given our - // compile-time checks. - direction as u32 as Self + match direction { + DataDirection::Bidirectional => Self::DMA_BIDIRECTIONAL, + DataDirection::ToDevice => Self::DMA_TO_DEVICE, + DataDirection::FromDevice => Self::DMA_FROM_DEVICE, + DataDirection::None => Self::DMA_NONE, + } } } -- 2.53.0