[{"id":3688141,"web_url":"http://patchwork.ozlabs.org/comment/3688141/","msgid":"<20260508035226.49139C2BCB0@smtp.kernel.org>","list_archive_url":null,"date":"2026-05-08T03:52:25","subject":"Re: [PATCH 01/18] rust: add untrusted data abstraction","submitter":{"id":93311,"url":"http://patchwork.ozlabs.org/api/people/93311/","name":null,"email":"sashiko-bot@kernel.org"},"content":"Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:\n- [High] Missing owned interface causes memory leaks for `Untrusted<MaybeUninit<T>>`.\n- [High] Calling `.len()` after `.as_mut_ptr()` on the same slice triggers Undefined Behavior under Stacked Borrows.\n- [Medium] Unaligned reference creation in `Validate` documentation examples triggers Undefined Behavior.\n- [Low] Missing `#[inline]` annotations on abstraction functions.\n- [Low] Nested imports violate the vertical import style guidelines.\n- [Low] Incomplete sentences, wrong examples, and inaccurate safety comments in documentation.\n--\n\ncommit 2a47d2c142208915fc2ad9542e62ff816065513b\nAuthor: Benno Lossin <lossin@kernel.org>\n\nrust: add untrusted data abstraction\n\nThis commit introduces the Untrusted and Unvalidated abstractions for handling\ndata from userspace or hardware. It uses the Validate trait to enforce\nvalidation before data can be safely accessed.\n\nMessage-ID: <20240925205244.873020-2-benno.lossin@proton.me>\n\n> diff --git a/rust/kernel/validate.rs b/rust/kernel/validate.rs\n> new file mode 100644\n> index 0000000000000..ae0aa20e27b47\n> --- /dev/null\n> +++ b/rust/kernel/validate.rs\n> @@ -0,0 +1,605 @@\n> +// SPDX-License-Identifier: GPL-2.0\n\n[ ... ]\n\n> +use crate::prelude::Init;\n> +use core::{\n> +    mem::MaybeUninit,\n> +    ops::{Index, IndexMut},\n> +    ptr, slice,\n> +};\n\nThis isn't a bug, but should ptr and slice be on separate lines to follow the\nvertical import style guidelines?\n\n[ ... ]\n\n> +impl<T: ?Sized> Untrusted<T> {\n> +    /// Marks the given value as untrusted.\n> +    ///\n> +    /// # Examples\n> +    ///\n> +    /// ```\n> +    /// use kernel::validate::Untrusted;\n> +    ///\n> +    /// # mod bindings { pub(crate) unsafe fn read_foo_info() -> [u8; 4] { todo!() } };\n> +    /// fn read_foo_info() -> Untrusted<[u8; 4]> {\n> +    ///     // SAFETY: just an FFI call without preconditions.\n> +    ///     Untrusted::new(unsafe { bindings::read_foo_info() })\n> +    /// }\n> +    /// ```\n> +    pub fn new(value: T) -> Self\n> +    where\n> +        T: Sized,\n> +    {\n> +        Self(Unvalidated::new(value))\n> +    }\n\nShould small abstraction functions like new(), new_ref(), new_mut(), and\nvalidate() be annotated with #[inline] per the Rust subsystem coding\nguidelines?\n\n[ ... ]\n\n> +    ///         // SAFETY: `data` returned by `foo_hardware_read` is valid for reads as long as the\n> +    ///         // `foo_hardware` object exists. That function updated the\n> +    ///         let data = unsafe { &mut *data };\n> +    ///         Ok(Untrusted::new_mut(data))\n> +    ///     }\n> +    /// }\n> +    /// ```\n> +    pub fn new_mut(value: &mut T) -> &mut Self {\n\nThis isn't a bug, but it looks like the comment sentence \"That function updated\nthe\" is incomplete.\n\n[ ... ]\n\n> +    /// Turns a slice of uninitialized, untrusted values into an untrusted slice of uninitialized\n> +    /// values.\n> +    pub fn transpose_slice_uninit(\n> +        slice: &[MaybeUninit<Untrusted<T>>],\n> +    ) -> &Untrusted<[MaybeUninit<T>]>\n> +    where\n> +        T: Sized,\n> +    {\n> +        let ptr = slice.as_ptr().cast::<MaybeUninit<T>>();\n> +        // SAFETY: `ptr` and `len` come from the same mutable slice reference.\n> +        let slice = unsafe { slice::from_raw_parts(ptr, slice.len()) };\n\nThis isn't a bug, but the safety comment mentions a \"mutable slice reference\",\nwhile the input slice is an immutable reference. Could this be corrected?\n\n> +        Untrusted::new_ref(slice)\n> +    }\n> +\n> +    /// Turns a slice of uninitialized, untrusted values into an untrusted slice of uninitialized\n> +    /// values.\n> +    pub fn transpose_slice_uninit_mut(\n> +        slice: &mut [MaybeUninit<Untrusted<T>>],\n> +    ) -> &mut Untrusted<[MaybeUninit<T>]>\n> +    where\n> +        T: Sized,\n> +    {\n> +        // CAST: `MaybeUninit<T>` and `MaybeUninit<Untrusted<T>>` have the same layout.\n> +        let ptr = slice.as_mut_ptr().cast::<MaybeUninit<T>>();\n> +        // SAFETY: `ptr` and `len` come from the same mutable slice reference.\n> +        let slice = unsafe { slice::from_raw_parts_mut(ptr, slice.len()) };\n\nCould calling slice.len() after slice.as_mut_ptr() trigger undefined behavior\nunder Stacked Borrows?\n\nCalling slice.len() creates a shared reference that invalidates the previously\nderived mutable raw pointer.\n\nShould the length be stored in a local variable before calling\nslice.as_mut_ptr()?\n\n> +        Untrusted::new_mut(slice)\n> +    }\n> +}\n> +\n> +impl<T> Untrusted<MaybeUninit<T>> {\n> +    /// Sets the underlying untrusted value.\n> +    ///\n> +    /// # Examples\n> +    ///\n> +    /// ```\n> +    /// use kernel::validate::Untrusted;\n> +    ///\n> +    /// let mut untrusted = Untrusted::new(42);\n> +    /// untrusted.write(24);\n> +    /// ```\n> +    pub fn write_uninit<E>(&mut self, value: impl Init<T, E>) -> Result<&mut Untrusted<T>, E> {\n\nThis isn't a bug, but the example initializes Untrusted::new(42) instead of\nusing MaybeUninit, and calls write() instead of write_uninit().\n\nAdditionally, does this interface leak owned resources?\n\nThere is no assume_init() or into_inner() method to consume the Untrusted\nMaybeUninit type by value and return the initialized Untrusted type.\n\nBecause MaybeUninit does not drop the inner type when it goes out of scope,\nit seems any initialized resource requiring a destructor will be permanently\nleaked.\n\n[ ... ]\n\n> +impl<T> Untrusted<[MaybeUninit<T>]> {\n> +    /// Sets the underlying untrusted value.\n> +    ///\n> +    /// # Examples\n> +    ///\n> +    /// ```\n> +    /// use kernel::validate::Untrusted;\n> +    ///\n> +    /// let mut untrusted = Untrusted::new(42);\n> +    /// untrusted.write(24);\n> +    /// ```\n> +    pub fn write_uninit_slice<E>(\n> +        &mut self,\n> +        value: impl Init<[T], E>,\n> +    ) -> Result<&mut Untrusted<[T]>, E> {\n> +        let ptr: *mut [MaybeUninit<T>] = &mut self.0 .0;\n> +        // CAST: `MaybeUninit<T>` is `repr(transparent)`.\n> +        let ptr = ptr as *mut [T];\n> +        // SAFETY: `ptr` came from a reference and if `Err` is returned, the underlying memory is\n> +        // considered uninitialized.\n> +        unsafe { value.__init(ptr) }.map(|()| {\n> +            let this = self.0.raw_mut().as_mut_ptr();\n> +            // CAST: `MaybeUninit<T>` is `repr(transparent)`.\n> +            let this = this.cast::<T>();\n> +            // SAFETY: `this` and `len` came from the same slice reference.\n> +            let this = unsafe { slice::from_raw_parts_mut(this, self.0.len()) };\n\nSimilar to transpose_slice_uninit_mut(), does calling self.0.len()\ninvalidate the mutable pointer derived from self.0.raw_mut().as_mut_ptr()?\n\n[ ... ]\n\n> +///         let ptr = raw.as_ptr();\n> +///         // CAST: `Data` only contains integers and has `repr(C)`.\n> +///         let ptr = ptr.cast::<Data>();\n> +///         // SAFETY: `ptr` came from a reference and the cast above is valid.\n> +///         Ok(unsafe { &*ptr })\n> +///     }\n> +/// }\n\nCould dereferencing this pointer trigger undefined behavior due to unaligned\naccess?\n\nA byte slice &[u8] only guarantees 1-byte alignment, so the resulting\npointer might not satisfy the 8-byte alignment required by the Data struct.\n\nShould the example verify alignment before dereferencing?\n\n[ ... ]\n\n> +///         // version 0 and 1 only use the lower 4 bits of flags\n> +///         if raw[1] & 0xf0 != 0 {\n> +///             return Err(EINVAL);\n> +///         }\n> +///         if raw[1] == 0 {}\n> +///         let ptr = raw.as_ptr();\n\nThis isn't a bug, but there appears to be an unused if block here.\n\n[ ... ]\n\n> +    fn new_ref(value: &T) -> &Self {\n> +        let ptr: *const T = value;\n> +        // CAST: `Self` is `repr(transparent)` and contains a `T`.\n> +        let ptr = ptr as *const Self;\n> +        // SAFETY: `ptr` came from a mutable reference valid for `'a`.\n> +        unsafe { &*ptr }\n> +    }\n\nThis isn't a bug, but the safety comment says the pointer came from a \"mutable\nreference\", yet the value is an immutable reference. Could this be fixed?","headers":{"Return-Path":"\n <linux-pci+bounces-54183-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-pci@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=nItJzaim;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=172.234.253.10; helo=sea.lore.kernel.org;\n envelope-from=linux-pci+bounces-54183-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=\"nItJzaim\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=10.30.226.201"],"Received":["from sea.lore.kernel.org (sea.lore.kernel.org [172.234.253.10])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4gBb2s1Wsdz1yCg\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 08 May 2026 13:59:01 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sea.lore.kernel.org (Postfix) with ESMTP id 88A16302D525\n\tfor <incoming@patchwork.ozlabs.org>; Fri,  8 May 2026 03:52:27 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id BE9602D0614;\n\tFri,  8 May 2026 03:52:26 +0000 (UTC)","from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org\n [10.30.226.201])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 9BD062C3266\n\tfor <linux-pci@vger.kernel.org>; Fri,  8 May 2026 03:52:26 +0000 (UTC)","by smtp.kernel.org (Postfix) with ESMTPSA id 49139C2BCB0;\n\tFri,  8 May 2026 03:52:26 +0000 (UTC)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1778212346; cv=none;\n b=t5LLH7SbshfUjl4I73aAq8YV7EDTEl9zoQzqfkNNm6CmeekjJXw99ZDH3NR7+W2R8I19brVCgKLm4advPgDov+bPdUg0d8QZ9bV37qejmDEsrvN5cZ0dYtwZOGhnMk6o6/Vn7Egz0+/qXirN6EwlrcM64/RiP/LFKgtdavHN1kU=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1778212346; c=relaxed/simple;\n\tbh=21BAkKHFtEC2SBbmi0/xyEMqLfQmNHIchfHxvegOBlQ=;\n\th=From:Subject:To:Cc:In-Reply-To:References:Content-Type:Date:\n\t Message-Id;\n b=nJmW0Ym7ggRtIH3PYhPcIbCNvm6DQybqM63Uui8WmZuKlHrHi4p+LqSBzlLhfODAesa0EVZGldOzLgxp+Or139GhxvA5ho/8u2EFV8Vf+5DQxbHjxfmHsinNUCabo4dmKKMVqaeiUxiRFKBlGIL7B7MFgygDdt1ZiGLM10sXC8M=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=nItJzaim; arc=none smtp.client-ip=10.30.226.201","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;\n\ts=k20201202; t=1778212346;\n\tbh=21BAkKHFtEC2SBbmi0/xyEMqLfQmNHIchfHxvegOBlQ=;\n\th=From:Subject:Reply-To:To:Cc:In-Reply-To:References:Date:From;\n\tb=nItJzaimk/rUxcwqj00km2JdIRlLh1YgeZlIBRdbZX/Ys/skt56NdxiF7tBr0BJIS\n\t 35ILp1XqzLb/Swpl62BQuWkMSLjt31VH8DbzrG5plr55D4mDbfcydbWunr76KJVT1e\n\t el4P9M4iLKp3qM+Y/yU0hIfx2DqWA+5jHsI8SYMo8Iu7ZBSvTPR5WptQmFqkhIRp0y\n\t Ly1L2WrY5cmKDXB+esUn+OFor5PGDgeUr5vIV65oJmpFeVsDQxBuXz7nfV8I1spngD\n\t jy6kX7LNwcrxyvdcf8uW9JsWFBQNZI5mwOlfH4gkCTKDBGLZhR2bl78g5tUCCPGaN/\n\t dacWYfwTsoxgw==","From":"sashiko-bot@kernel.org","Subject":"Re: [PATCH 01/18] rust: add untrusted data abstraction","Reply-To":"sashiko@lists.linux.dev","To":"alistair23@gmail.com","Cc":"linux-pci@vger.kernel.org, ojeda@kernel.org","In-Reply-To":"<20260508031710.514574-2-alistair.francis@wdc.com>","References":"<20260508031710.514574-2-alistair.francis@wdc.com>","Content-Type":"text/plain; charset=utf-8","Content-Transfer-Encoding":"quoted-printable","Date":"Fri, 08 May 2026 03:52:25 +0000","Message-Id":"<20260508035226.49139C2BCB0@smtp.kernel.org>","Precedence":"bulk","X-Mailing-List":"linux-pci@vger.kernel.org","List-Id":"<linux-pci.vger.kernel.org>","List-Subscribe":"<mailto:linux-pci+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-pci+unsubscribe@vger.kernel.org>"}},{"id":3688166,"web_url":"http://patchwork.ozlabs.org/comment/3688166/","msgid":"<73b1ecdf-8754-4c17-88af-671246a6787d@de.bosch.com>","list_archive_url":null,"date":"2026-05-08T05:17:53","subject":"Re: [PATCH 01/18] rust: add untrusted data abstraction","submitter":{"id":10121,"url":"http://patchwork.ozlabs.org/api/people/10121/","name":"Dirk Behme","email":"dirk.behme@de.bosch.com"},"content":"Hi Alistair,\n\nOn 08.05.2026 05:16, alistair23@gmail.com wrote:\n> From: Benno Lossin <benno.lossin@proton.me>\n> \n> When reading data from userspace, hardware or other external untrusted\n> sources, the data must be validated before it is used for logic within\n> the kernel. This abstraction provides a generic newtype wrapper\n> `Untrusted`; it prevents direct access to the inner type. The only way\n> to use the underlying data is to call `.validate()` on such a value.\n> \n> Doing so utilizes the new `Validate` trait that is responsible for all\n> of the validation logic. This trait gives access to the inner value of\n> `Untrusted` by means of another newtype wrapper `Unvalidated`. In\n> contrast to `Untrusted`, `Unvalidated` allows direct access and\n> additionally provides several helper functions for slices.\n> \n> Having these two different newtype wrappers is an idea from Simona\n> Vetter. It has several benefits: it fully prevents safe access to the\n> underlying value of `Untrusted` without going through the `Validate`\n> API. Additionally, it allows one to grep for validation logic by simply\n> looking for `Unvalidated<`.\n> \n> Any API that reads data from an untrusted source should return\n> `Untrusted<T>` where `T` is the type of the underlying untrusted data.\n> This generic allows other abstractions to return their custom type\n> wrapped by `Untrusted`, signaling to the caller that the data must be\n> validated before use. This allows those abstractions to be used both in\n> a trusted and untrusted manner, increasing their generality.\n> Additionally, using the arbitrary self types feature, APIs can be\n> designed to explicitly read untrusted data:\n> \n>      impl MyCustomDataSource {\n>          pub fn read(self: &Untrusted<Self>) -> &Untrusted<[u8]>;\n>      }\n> \n> Cc: Simona Vetter <simona.vetter@ffwll.ch>\n> Signed-off-by: Benno Lossin <benno.lossin@proton.me>\n> Message-ID: <20240925205244.873020-2-benno.lossin@proton.me>\n\n\nToday, randomly, I was about to ask Benno if there are any plans to \ncontinue with his great untrusted work. Just to find that you are \ncarrying this forward. Many thanks!\n\nWhile trying to figure out some history of this patch, it looks to me \nthat the version you are using is Benno's v2:\n\nhttps://lore.kernel.org/rust-for-linux/20240925205244.873020-2-benno.lossin@proton.me/\n\n?\n\nWhile the latest version from Benno I found is a v4:\n\nhttps://lore.kernel.org/rust-for-linux/20250814124424.516191-3-lossin@kernel.org/\n\nIs there any reason not to use that?\n\nWhile at this, do you have any plan to add the `Validate` trait as well?\n\nhttps://lore.kernel.org/rust-for-linux/20250814124424.516191-4-lossin@kernel.org/\n\nThanks\n\nDirk\n\nP.S.: Carrying this patch forward, please check if it needs an update \nregarding new \"rules\". E.g. it looks to me that there should be an \nupdate regarding the vertical style for imports?\n\nhttps://docs.kernel.org/rust/coding-guidelines.html#imports\n\n\n> ---\n>   rust/kernel/lib.rs      |   1 +\n>   rust/kernel/validate.rs | 605 ++++++++++++++++++++++++++++++++++++++++\n>   2 files changed, 606 insertions(+)\n>   create mode 100644 rust/kernel/validate.rs\n> \n> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs\n> index b72b2fbe046d..fe580fde609f 100644\n> --- a/rust/kernel/lib.rs\n> +++ b/rust/kernel/lib.rs\n> @@ -133,6 +133,7 @@\n>   pub mod uaccess;\n>   #[cfg(CONFIG_USB = \"y\")]\n>   pub mod usb;\n> +pub mod validate;\n>   pub mod workqueue;\n>   pub mod xarray;\n>   \n> diff --git a/rust/kernel/validate.rs b/rust/kernel/validate.rs\n> new file mode 100644\n> index 000000000000..ae0aa20e27b4\n> --- /dev/null\n> +++ b/rust/kernel/validate.rs\n> @@ -0,0 +1,605 @@\n> +// SPDX-License-Identifier: GPL-2.0\n> +\n> +//! Types for handling and validating untrusted data.\n> +//!\n> +//! # Overview\n> +//!\n> +//! Untrusted data is marked using the [`Untrusted<T>`] type. See [Rationale](#rationale) for the\n> +//! reasons to mark untrusted data throughout the kernel. It is a totally opaque wrapper, it is not\n> +//! possible to read the data inside; but it is possible to [`Untrusted::write`] into it.\n> +//!\n> +//! The only way to \"access\" the data inside an [`Untrusted<T>`] is to [`Untrusted::validate`] it;\n> +//! turning it into a different form using the [`Validate`] trait. That trait receives the data in\n> +//! the form of [`Unvalidated<T>`], which in contrast to [`Untrusted<T>`], allows access to the\n> +//! underlying data. It additionally provides several utility functions to simplify validation.\n> +//!\n> +//! # Rationale\n> +//!\n> +//! When reading data from an untrusted source, it must be validated before it can be used for\n> +//! logic. For example, this is a very bad idea:\n> +//!\n> +//! ```\n> +//! # fn read_bytes_from_network() -> Box<[u8]> {\n> +//! #     Box::new([1, 0], kernel::alloc::flags::GFP_KERNEL).unwrap()\n> +//! # }\n> +//! let bytes: Box<[u8]> = read_bytes_from_network();\n> +//! let data_index = bytes[0];\n> +//! let data = bytes[usize::from(data_index)];\n> +//! ```\n> +//!\n> +//! While this will not lead to a memory violation (because the array index checks the bounds), it\n> +//! might result in a kernel panic. For this reason, all untrusted data must be wrapped in\n> +//! [`Untrusted<T>`]. This type only allows validating the data or passing it along, since copying\n> +//! data from one userspace buffer into another is allowed for untrusted data.\n> +\n> +use crate::prelude::Init;\n> +use core::{\n> +    mem::MaybeUninit,\n> +    ops::{Index, IndexMut},\n> +    ptr, slice,\n> +};\n> +\n> +/// Untrusted data of type `T`.\n> +///\n> +/// When reading data from userspace, hardware or other external untrusted sources, the data must\n> +/// be validated before it is used for logic within the kernel. To do so, the [`validate()`]\n> +/// function exists and uses the [`Validate`] trait.\n> +///\n> +/// Also see the [module] description.\n> +///\n> +/// [`validate()`]: Self::validate\n> +/// [module]: self\n> +#[repr(transparent)]\n> +pub struct Untrusted<T: ?Sized>(Unvalidated<T>);\n> +\n> +impl<T: ?Sized> Untrusted<T> {\n> +    /// Marks the given value as untrusted.\n> +    ///\n> +    /// # Examples\n> +    ///\n> +    /// ```\n> +    /// use kernel::validate::Untrusted;\n> +    ///\n> +    /// # mod bindings { pub(crate) unsafe fn read_foo_info() -> [u8; 4] { todo!() } };\n> +    /// fn read_foo_info() -> Untrusted<[u8; 4]> {\n> +    ///     // SAFETY: just an FFI call without preconditions.\n> +    ///     Untrusted::new(unsafe { bindings::read_foo_info() })\n> +    /// }\n> +    /// ```\n> +    pub fn new(value: T) -> Self\n> +    where\n> +        T: Sized,\n> +    {\n> +        Self(Unvalidated::new(value))\n> +    }\n> +\n> +    /// Marks the value behind the reference as untrusted.\n> +    ///\n> +    /// # Examples\n> +    ///\n> +    /// In this imaginary example there exists the `foo_hardware` struct on the C side, as well as\n> +    /// a `foo_hardware_read` function that reads some data directly from the hardware.\n> +    /// ```\n> +    /// use kernel::{error, types::Opaque, validate::Untrusted};\n> +    /// use core::ptr;\n> +    ///\n> +    /// # #[allow(non_camel_case_types)]\n> +    /// # mod bindings {\n> +    /// #     pub(crate) struct foo_hardware;\n> +    /// #     pub(crate) unsafe fn foo_hardware_read(_foo: *mut foo_hardware, _len: &mut usize) -> *mut u8 {\n> +    /// #         todo!()\n> +    /// #     }\n> +    /// # }\n> +    /// struct Foo(Opaque<bindings::foo_hardware>);\n> +    ///\n> +    /// impl Foo {\n> +    ///     fn read(&mut self, mut len: usize) -> Result<&Untrusted<[u8]>> {\n> +    ///         // SAFETY: just an FFI call without preconditions.\n> +    ///         let data: *mut u8 = unsafe { bindings::foo_hardware_read(self.0.get(), &mut len) };\n> +    ///         let data = error::from_err_ptr(data)?;\n> +    ///         let data = ptr::slice_from_raw_parts(data, len);\n> +    ///         // SAFETY: `data` returned by `foo_hardware_read` is valid for reads as long as the\n> +    ///         // `foo_hardware` object exists. That function updated the\n> +    ///         let data = unsafe { &*data };\n> +    ///         Ok(Untrusted::new_ref(data))\n> +    ///     }\n> +    /// }\n> +    /// ```\n> +    pub fn new_ref(value: &T) -> &Self {\n> +        let ptr: *const T = value;\n> +        // CAST: `Self` and `Unvalidated` are `repr(transparent)` and contain a `T`.\n> +        let ptr = ptr as *const Self;\n> +        // SAFETY: `ptr` came from a shared reference valid for `'a`.\n> +        unsafe { &*ptr }\n> +    }\n> +\n> +    /// Marks the value behind the reference as untrusted.\n> +    ///\n> +    /// # Examples\n> +    ///\n> +    /// In this imaginary example there exists the `foo_hardware` struct on the C side, as well as\n> +    /// a `foo_hardware_read` function that reads some data directly from the hardware.\n> +    /// ```\n> +    /// use kernel::{error, types::Opaque, validate::Untrusted};\n> +    /// use core::ptr;\n> +    ///\n> +    /// # #[allow(non_camel_case_types)]\n> +    /// # mod bindings {\n> +    /// #     pub(crate) struct foo_hardware;\n> +    /// #     pub(crate) unsafe fn foo_hardware_read(_foo: *mut foo_hardware, _len: &mut usize) -> *mut u8 {\n> +    /// #         todo!()\n> +    /// #     }\n> +    /// # }\n> +    /// struct Foo(Opaque<bindings::foo_hardware>);\n> +    ///\n> +    /// impl Foo {\n> +    ///     fn read(&mut self, mut len: usize) -> Result<&mut Untrusted<[u8]>> {\n> +    ///         // SAFETY: just an FFI call without preconditions.\n> +    ///         let data: *mut u8 = unsafe { bindings::foo_hardware_read(self.0.get(), &mut len) };\n> +    ///         let data = error::from_err_ptr(data)?;\n> +    ///         let data = ptr::slice_from_raw_parts_mut(data, len);\n> +    ///         // SAFETY: `data` returned by `foo_hardware_read` is valid for reads as long as the\n> +    ///         // `foo_hardware` object exists. That function updated the\n> +    ///         let data = unsafe { &mut *data };\n> +    ///         Ok(Untrusted::new_mut(data))\n> +    ///     }\n> +    /// }\n> +    /// ```\n> +    pub fn new_mut(value: &mut T) -> &mut Self {\n> +        let ptr: *mut T = value;\n> +        // CAST: `Self` and `Unvalidated` are `repr(transparent)` and contain a `T`.\n> +        let ptr = ptr as *mut Self;\n> +        // SAFETY: `ptr` came from a mutable reference valid for `'a`.\n> +        unsafe { &mut *ptr }\n> +    }\n> +\n> +    /// Validates and parses the untrusted data.\n> +    ///\n> +    /// See the [`Validate`] trait on how to implement it.\n> +    pub fn validate<'a, V: Validate<&'a Unvalidated<T>>>(&'a self) -> Result<V, V::Err> {\n> +        V::validate(&self.0)\n> +    }\n> +\n> +    /// Validates and parses the untrusted data.\n> +    ///\n> +    /// See the [`Validate`] trait on how to implement it.\n> +    pub fn validate_mut<'a, V: Validate<&'a mut Unvalidated<T>>>(\n> +        &'a mut self,\n> +    ) -> Result<V, V::Err> {\n> +        V::validate(&mut self.0)\n> +    }\n> +\n> +    /// Sets the underlying untrusted value.\n> +    ///\n> +    /// # Examples\n> +    ///\n> +    /// ```\n> +    /// use kernel::validate::Untrusted;\n> +    ///\n> +    /// let mut untrusted = Untrusted::new(42);\n> +    /// untrusted.write(24);\n> +    /// ```\n> +    pub fn write(&mut self, value: impl Init<T>) {\n> +        let ptr: *mut T = &mut self.0 .0;\n> +        // SAFETY: `ptr` came from a mutable reference and the value is overwritten before it is\n> +        // read.\n> +        unsafe { ptr::drop_in_place(ptr) };\n> +        // SAFETY: `ptr` came from a mutable reference and the initializer cannot error.\n> +        match unsafe { value.__init(ptr) } {\n> +            Ok(()) => {}\n> +            Err(_) => unreachable!(),\n> +        }\n> +    }\n> +\n> +    /// Turns a slice of untrusted values into an untrusted slice of values.\n> +    pub fn transpose_slice(slice: &[Untrusted<T>]) -> &Untrusted<[T]>\n> +    where\n> +        T: Sized,\n> +    {\n> +        let ptr = slice.as_ptr().cast::<T>();\n> +        // SAFETY: `ptr` and `len` come from the same slice reference.\n> +        let slice = unsafe { slice::from_raw_parts(ptr, slice.len()) };\n> +        Untrusted::new_ref(slice)\n> +    }\n> +\n> +    /// Turns a slice of uninitialized, untrusted values into an untrusted slice of uninitialized\n> +    /// values.\n> +    pub fn transpose_slice_uninit(\n> +        slice: &[MaybeUninit<Untrusted<T>>],\n> +    ) -> &Untrusted<[MaybeUninit<T>]>\n> +    where\n> +        T: Sized,\n> +    {\n> +        let ptr = slice.as_ptr().cast::<MaybeUninit<T>>();\n> +        // SAFETY: `ptr` and `len` come from the same mutable slice reference.\n> +        let slice = unsafe { slice::from_raw_parts(ptr, slice.len()) };\n> +        Untrusted::new_ref(slice)\n> +    }\n> +\n> +    /// Turns a slice of uninitialized, untrusted values into an untrusted slice of uninitialized\n> +    /// values.\n> +    pub fn transpose_slice_uninit_mut(\n> +        slice: &mut [MaybeUninit<Untrusted<T>>],\n> +    ) -> &mut Untrusted<[MaybeUninit<T>]>\n> +    where\n> +        T: Sized,\n> +    {\n> +        // CAST: `MaybeUninit<T>` and `MaybeUninit<Untrusted<T>>` have the same layout.\n> +        let ptr = slice.as_mut_ptr().cast::<MaybeUninit<T>>();\n> +        // SAFETY: `ptr` and `len` come from the same mutable slice reference.\n> +        let slice = unsafe { slice::from_raw_parts_mut(ptr, slice.len()) };\n> +        Untrusted::new_mut(slice)\n> +    }\n> +}\n> +\n> +impl<T> Untrusted<MaybeUninit<T>> {\n> +    /// Sets the underlying untrusted value.\n> +    ///\n> +    /// # Examples\n> +    ///\n> +    /// ```\n> +    /// use kernel::validate::Untrusted;\n> +    ///\n> +    /// let mut untrusted = Untrusted::new(42);\n> +    /// untrusted.write(24);\n> +    /// ```\n> +    pub fn write_uninit<E>(&mut self, value: impl Init<T, E>) -> Result<&mut Untrusted<T>, E> {\n> +        let ptr: *mut MaybeUninit<T> = &mut self.0 .0;\n> +        // CAST: `MaybeUninit<T>` is `repr(transparent)`.\n> +        let ptr = ptr.cast::<T>();\n> +        // SAFETY: `ptr` came from a reference and if `Err` is returned, the underlying memory is\n> +        // considered uninitialized.\n> +        unsafe { value.__init(ptr) }.map(|()| {\n> +            let this = self.0.raw_mut();\n> +            // SAFETY: we initialized the memory above.\n> +            Untrusted::new_mut(unsafe { this.assume_init_mut() })\n> +        })\n> +    }\n> +}\n> +\n> +impl<T> Untrusted<[MaybeUninit<T>]> {\n> +    /// Sets the underlying untrusted value.\n> +    ///\n> +    /// # Examples\n> +    ///\n> +    /// ```\n> +    /// use kernel::validate::Untrusted;\n> +    ///\n> +    /// let mut untrusted = Untrusted::new(42);\n> +    /// untrusted.write(24);\n> +    /// ```\n> +    pub fn write_uninit_slice<E>(\n> +        &mut self,\n> +        value: impl Init<[T], E>,\n> +    ) -> Result<&mut Untrusted<[T]>, E> {\n> +        let ptr: *mut [MaybeUninit<T>] = &mut self.0 .0;\n> +        // CAST: `MaybeUninit<T>` is `repr(transparent)`.\n> +        let ptr = ptr as *mut [T];\n> +        // SAFETY: `ptr` came from a reference and if `Err` is returned, the underlying memory is\n> +        // considered uninitialized.\n> +        unsafe { value.__init(ptr) }.map(|()| {\n> +            let this = self.0.raw_mut().as_mut_ptr();\n> +            // CAST: `MaybeUninit<T>` is `repr(transparent)`.\n> +            let this = this.cast::<T>();\n> +            // SAFETY: `this` and `len` came from the same slice reference.\n> +            let this = unsafe { slice::from_raw_parts_mut(this, self.0.len()) };\n> +            Untrusted::new_mut(this)\n> +        })\n> +    }\n> +}\n> +\n> +/// Marks types that can be used as input to [`Validate::validate`].\n> +pub trait ValidateInput: private::Sealed + Sized {}\n> +\n> +mod private {\n> +    pub trait Sealed {}\n> +}\n> +\n> +impl<'a, T: ?Sized> private::Sealed for &'a Unvalidated<T> {}\n> +impl<'a, T: ?Sized> ValidateInput for &'a Unvalidated<T> {}\n> +\n> +impl<'a, T: ?Sized> private::Sealed for &'a mut Unvalidated<T> {}\n> +impl<'a, T: ?Sized> ValidateInput for &'a mut Unvalidated<T> {}\n> +\n> +/// Validates untrusted data.\n> +///\n> +/// # Examples\n> +///\n> +/// The simplest way to validate data is to just implement `Validate<&Unvalidated<[u8]>>` for the\n> +/// type that you wish to validate:\n> +///\n> +/// ```\n> +/// use kernel::{\n> +///     error::{code::EINVAL, Error},\n> +///     str::{CStr, CString},\n> +///     validate::{Unvalidated, Validate},\n> +/// };\n> +///\n> +/// struct Data {\n> +///     flags: u8,\n> +///     name: CString,\n> +/// }\n> +///\n> +/// impl Validate<&Unvalidated<[u8]>> for Data {\n> +///     type Err = Error;\n> +///\n> +///     fn validate(unvalidated: &Unvalidated<[u8]>) -> Result<Self, Self::Err> {\n> +///         let raw = unvalidated.raw();\n> +///         let (&flags, name) = raw.split_first().ok_or(EINVAL)?;\n> +///         let name = CStr::from_bytes_with_nul(name)?.to_cstring()?;\n> +///         Ok(Data { flags, name })\n> +///     }\n> +/// }\n> +/// ```\n> +///\n> +/// This approach copies the data and requires allocation. If you want to avoid the allocation and\n> +/// copying the data, you can borrow from the input like this:\n> +///\n> +/// ```\n> +/// use kernel::{\n> +///     error::{code::EINVAL, Error},\n> +///     str::CStr,\n> +///     validate::{Unvalidated, Validate},\n> +/// };\n> +///\n> +/// struct Data<'a> {\n> +///     flags: u8,\n> +///     name: &'a CStr,\n> +/// }\n> +///\n> +/// impl<'a> Validate<&'a Unvalidated<[u8]>> for Data<'a> {\n> +///     type Err = Error;\n> +///\n> +///     fn validate(unvalidated: &'a Unvalidated<[u8]>) -> Result<Self, Self::Err> {\n> +///         let raw = unvalidated.raw();\n> +///         let (&flags, name) = raw.split_first().ok_or(EINVAL)?;\n> +///         let name = CStr::from_bytes_with_nul(name)?;\n> +///         Ok(Data { flags, name })\n> +///     }\n> +/// }\n> +/// ```\n> +///\n> +/// If you need to in-place validate your data, you currently need to resort to `unsafe`:\n> +///\n> +/// ```\n> +/// use kernel::{\n> +///     error::{code::EINVAL, Error},\n> +///     str::CStr,\n> +///     validate::{Unvalidated, Validate},\n> +/// };\n> +/// use core::mem;\n> +///\n> +/// // Important: use `repr(C)`, this ensures a linear layout of this type.\n> +/// #[repr(C)]\n> +/// struct Data {\n> +///     version: u8,\n> +///     flags: u8,\n> +///     _reserved: [u8; 2],\n> +///     count: u64,\n> +///     // lots of other fields...\n> +/// }\n> +///\n> +/// impl Validate<&Unvalidated<[u8]>> for &Data {\n> +///     type Err = Error;\n> +///\n> +///     fn validate(unvalidated: &Unvalidated<[u8]>) -> Result<Self, Self::Err> {\n> +///         let raw = unvalidated.raw();\n> +///         if raw.len() < mem::size_of::<Data>() {\n> +///             return Err(EINVAL);\n> +///         }\n> +///         // can only handle version 0\n> +///         if raw[0] != 0 {\n> +///             return Err(EINVAL);\n> +///         }\n> +///         // version 0 only uses the lower 4 bits of flags\n> +///         if raw[1] & 0xf0 != 0 {\n> +///             return Err(EINVAL);\n> +///         }\n> +///         let ptr = raw.as_ptr();\n> +///         // CAST: `Data` only contains integers and has `repr(C)`.\n> +///         let ptr = ptr.cast::<Data>();\n> +///         // SAFETY: `ptr` came from a reference and the cast above is valid.\n> +///         Ok(unsafe { &*ptr })\n> +///     }\n> +/// }\n> +/// ```\n> +///\n> +/// To be able to modify the parsed data, while still supporting zero-copy, you can implement\n> +/// `Validate<&mut Unvalidated<[u8]>>`:\n> +///\n> +/// ```\n> +/// use kernel::{\n> +///     error::{code::EINVAL, Error},\n> +///     str::CStr,\n> +///     validate::{Unvalidated, Validate},\n> +/// };\n> +/// use core::mem;\n> +///\n> +/// // Important: use `repr(C)`, this ensures a linear layout of this type.\n> +/// #[repr(C)]\n> +/// struct Data {\n> +///     version: u8,\n> +///     flags: u8,\n> +///     _reserved: [u8; 2],\n> +///     count: u64,\n> +///     // lots of other fields...\n> +/// }\n> +///\n> +/// impl Validate<&mut Unvalidated<[u8]>> for &Data {\n> +///     type Err = Error;\n> +///\n> +///     fn validate(unvalidated: &mut Unvalidated<[u8]>) -> Result<Self, Self::Err> {\n> +///         let raw = unvalidated.raw_mut();\n> +///         if raw.len() < mem::size_of::<Data>() {\n> +///             return Err(EINVAL);\n> +///         }\n> +///         match raw[0] {\n> +///             0 => {},\n> +///             1 => {\n> +///                 // version 1 implicitly sets the first bit.\n> +///                 raw[1] |= 1;\n> +///             },\n> +///             // can only handle version 0 and 1\n> +///             _ => return Err(EINVAL),\n> +///         }\n> +///         // version 0 and 1 only use the lower 4 bits of flags\n> +///         if raw[1] & 0xf0 != 0 {\n> +///             return Err(EINVAL);\n> +///         }\n> +///         if raw[1] == 0 {}\n> +///         let ptr = raw.as_ptr();\n> +///         // CAST: `Data` only contains integers and has `repr(C)`.\n> +///         let ptr = ptr.cast::<Data>();\n> +///         // SAFETY: `ptr` came from a reference and the cast above is valid.\n> +///         Ok(unsafe { &*ptr })\n> +///     }\n> +/// }\n> +/// ```\n> +pub trait Validate<I: ValidateInput>: Sized {\n> +    /// Validation error.\n> +    type Err;\n> +\n> +    /// Validate the given untrusted data and parse it into the output type.\n> +    fn validate(unvalidated: I) -> Result<Self, Self::Err>;\n> +}\n> +\n> +/// Unvalidated data of type `T`.\n> +#[repr(transparent)]\n> +pub struct Unvalidated<T: ?Sized>(T);\n> +\n> +impl<T: ?Sized> Unvalidated<T> {\n> +    fn new(value: T) -> Self\n> +    where\n> +        T: Sized,\n> +    {\n> +        Self(value)\n> +    }\n> +\n> +    fn new_ref(value: &T) -> &Self {\n> +        let ptr: *const T = value;\n> +        // CAST: `Self` is `repr(transparent)` and contains a `T`.\n> +        let ptr = ptr as *const Self;\n> +        // SAFETY: `ptr` came from a mutable reference valid for `'a`.\n> +        unsafe { &*ptr }\n> +    }\n> +\n> +    fn new_mut(value: &mut T) -> &mut Self {\n> +        let ptr: *mut T = value;\n> +        // CAST: `Self` is `repr(transparent)` and contains a `T`.\n> +        let ptr = ptr as *mut Self;\n> +        // SAFETY: `ptr` came from a mutable reference valid for `'a`.\n> +        unsafe { &mut *ptr }\n> +    }\n> +\n> +    /// Validates and parses the untrusted data.\n> +    ///\n> +    /// See the [`Validate`] trait on how to implement it.\n> +    pub fn validate_ref<'a, V: Validate<&'a Unvalidated<T>>>(&'a self) -> Result<V, V::Err> {\n> +        V::validate(self)\n> +    }\n> +\n> +    /// Validates and parses the untrusted data.\n> +    ///\n> +    /// See the [`Validate`] trait on how to implement it.\n> +    pub fn validate_mut<'a, V: Validate<&'a mut Unvalidated<T>>>(\n> +        &'a mut self,\n> +    ) -> Result<V, V::Err> {\n> +        V::validate(self)\n> +    }\n> +\n> +    /// Gives immutable access to the underlying value.\n> +    pub fn raw(&self) -> &T {\n> +        &self.0\n> +    }\n> +\n> +    /// Gives mutable access to the underlying value.\n> +    pub fn raw_mut(&mut self) -> &mut T {\n> +        &mut self.0\n> +    }\n> +}\n> +\n> +impl<T, I> Index<I> for Unvalidated<[T]>\n> +where\n> +    I: slice::SliceIndex<[T]>,\n> +{\n> +    type Output = Unvalidated<I::Output>;\n> +\n> +    fn index(&self, index: I) -> &Self::Output {\n> +        Unvalidated::new_ref(self.0.index(index))\n> +    }\n> +}\n> +\n> +impl<T, I> IndexMut<I> for Unvalidated<[T]>\n> +where\n> +    I: slice::SliceIndex<[T]>,\n> +{\n> +    fn index_mut(&mut self, index: I) -> &mut Self::Output {\n> +        Unvalidated::new_mut(self.0.index_mut(index))\n> +    }\n> +}\n> +\n> +/// Immutable unvalidated slice iterator.\n> +pub struct Iter<'a, T>(slice::Iter<'a, T>);\n> +\n> +/// Mutable unvalidated slice iterator.\n> +pub struct IterMut<'a, T>(slice::IterMut<'a, T>);\n> +\n> +impl<'a, T> Iterator for Iter<'a, T> {\n> +    type Item = &'a Unvalidated<T>;\n> +\n> +    fn next(&mut self) -> Option<Self::Item> {\n> +        self.0.next().map(Unvalidated::new_ref)\n> +    }\n> +}\n> +\n> +impl<'a, T> IntoIterator for &'a Unvalidated<[T]> {\n> +    type Item = &'a Unvalidated<T>;\n> +    type IntoIter = Iter<'a, T>;\n> +\n> +    fn into_iter(self) -> Self::IntoIter {\n> +        Iter(self.0.iter())\n> +    }\n> +}\n> +\n> +impl<'a, T> Iterator for IterMut<'a, T> {\n> +    type Item = &'a mut Unvalidated<T>;\n> +\n> +    fn next(&mut self) -> Option<Self::Item> {\n> +        self.0.next().map(Unvalidated::new_mut)\n> +    }\n> +}\n> +\n> +impl<'a, T> IntoIterator for &'a mut Unvalidated<[T]> {\n> +    type Item = &'a mut Unvalidated<T>;\n> +    type IntoIter = IterMut<'a, T>;\n> +\n> +    fn into_iter(self) -> Self::IntoIter {\n> +        IterMut(self.0.iter_mut())\n> +    }\n> +}\n> +\n> +impl<T> Unvalidated<[T]> {\n> +    /// Returns the number of elements in the underlying slice.\n> +    pub fn len(&self) -> usize {\n> +        self.0.len()\n> +    }\n> +\n> +    /// Returns true if the underlying slice has a length of 0.\n> +    pub fn is_empty(&self) -> bool {\n> +        self.0.is_empty()\n> +    }\n> +\n> +    /// Iterates over all items and validates each of them individually.\n> +    pub fn validate_iter<'a, V: Validate<&'a Unvalidated<T>>>(\n> +        &'a self,\n> +    ) -> impl Iterator<Item = Result<V, V::Err>> + 'a {\n> +        self.into_iter().map(|item| V::validate(item))\n> +    }\n> +\n> +    /// Iterates over all items and validates each of them individually.\n> +    pub fn validate_iter_mut<'a, V: Validate<&'a mut Unvalidated<T>>>(\n> +        &'a mut self,\n> +    ) -> impl Iterator<Item = Result<V, V::Err>> + 'a {\n> +        self.into_iter().map(|item| V::validate(item))\n> +    }\n> +}","headers":{"Return-Path":"\n <linux-pci+bounces-54222-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-pci@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=de.bosch.com header.i=@de.bosch.com header.a=rsa-sha256\n header.s=selector2 header.b=Wz6AWPRp;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c04:e001:36c::12fc:5321; helo=tor.lore.kernel.org;\n envelope-from=linux-pci+bounces-54222-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=de.bosch.com header.i=@de.bosch.com\n header.b=\"Wz6AWPRp\"","smtp.subspace.kernel.org;\n arc=fail smtp.client-ip=40.107.159.53","smtp.subspace.kernel.org;\n dmarc=pass (p=reject dis=none) header.from=de.bosch.com","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=de.bosch.com"],"Received":["from tor.lore.kernel.org (tor.lore.kernel.org\n [IPv6:2600:3c04:e001:36c::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4gBcpL6GB4z1yK7\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 08 May 2026 15:18:18 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby tor.lore.kernel.org (Postfix) with ESMTP id 0AF1530398B5\n\tfor <incoming@patchwork.ozlabs.org>; Fri,  8 May 2026 05:18:15 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 6EE101B6527;\n\tFri,  8 May 2026 05:18:11 +0000 (UTC)","from OSPPR02CU001.outbound.protection.outlook.com\n (mail-norwayeastazon11013053.outbound.protection.outlook.com [40.107.159.53])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 75FCF3385B9;\n\tFri,  8 May 2026 05:18:06 +0000 (UTC)","from AS4P195CA0036.EURP195.PROD.OUTLOOK.COM (2603:10a6:20b:65a::29)\n by AMBPR10MB9928.EURPRD10.PROD.OUTLOOK.COM (2603:10a6:20b:760::13) with\n Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9891.19; Fri, 8 May\n 2026 05:18:00 +0000","from AM1PEPF000252E1.eurprd07.prod.outlook.com\n (2603:10a6:20b:65a:cafe::90) by AS4P195CA0036.outlook.office365.com\n (2603:10a6:20b:65a::29) with Microsoft SMTP Server (version=TLS1_3,\n cipher=TLS_AES_256_GCM_SHA384) id 15.20.9891.19 via Frontend Transport; Fri,\n 8 May 2026 05:18:00 +0000","from eop.bosch-org.com (139.15.153.206) by\n AM1PEPF000252E1.mail.protection.outlook.com (10.167.16.59) with Microsoft\n SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n 15.20.9891.9 via Frontend Transport; Fri, 8 May 2026 05:18:00 +0000","from RNGMBX3002.de.bosch.com (10.124.11.207) by eop.bosch-org.com\n (139.15.153.206) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.37; Fri, 8 May\n 2026 07:18:00 +0200","from [10.34.218.123] (10.34.218.123) by smtp.app.bosch.com\n (10.124.11.207) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.37; Fri, 8 May\n 2026 07:17:59 +0200"],"ARC-Seal":["i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1778217491; cv=fail;\n b=UhMzXq6sVJUG7h57Xj1GKKIJEfw3d1d3pG9gmI3E0yvIGAFoL5kvzfmgSdsEXvxS0C09YXNvMoo+XAbFdwlpeTeJfA8qNbLIokL/5t0i7J5GlS+Hia05gTvc7ZxuibmS3ongisDXl3nZM65GOk/m3H8FzsZkVAGbhiHY93fO9iE=","i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none;\n b=T9e9UYmtQxHizYH7vN3rK4eJ6pCaRTNMtnu95lhBqwLDEvRu+dUMldJCm7WMhIE7qUDdIjUUOXjMG99I9C0XO+Cwk32HeoerRUbCg7KOc4Xf0uQsycUDs//pKhJtvm/NBcKoqyvSH8f117mMraTGlvkRQtUDqHsgvaWNlfJrlwcpW9YVeDPDNxRQ88/1xJ15pmrpyrP4aeGmPrEhenhHfYGIKfcTnCeQiYY4mudNgrgeuVKbs5GXTDC7mpWXJwh++V23RbiE8c+NIvr0GXppb9hDYof55TKV3xlodidvc5C8XgHCKttZT4nPuZJ6hjE+0HAvakL8oLN/amPCNe1Lpg=="],"ARC-Message-Signature":["i=2; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1778217491; c=relaxed/simple;\n\tbh=DV51e49o7Caea9bXKkQmendSgm6vv5LYIGFjPyQqJZ8=;\n\th=Message-ID:Date:MIME-Version:Subject:To:CC:References:From:\n\t In-Reply-To:Content-Type;\n b=oPw4W88NAyDcZNeA6aLZEPmU3B9KC6qdN0i0A5RStNY0UAEtx9LcOO59ZUFElmnhcH5+t5hICFXMcO2Ic0i61iCVk+iCDmhhffSrU5aHnzwu33I8wg9UT/713gv2Cd6IusvMkQw2LL5BKHt65BAHVJ72ZsBb1qh77n4HRzJGzs8=","i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n s=arcselector10001;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;\n bh=YqEzi7YNHEHsRMKBzCrW3g5ZjWsuEVI2+ztfiZbnYDQ=;\n b=mQu+dPsVfH+99JtAM/aMauLJyWl8sZCUCsJP7/2XOovgoJrtsuSUqJvHOFfdwBNLZJ1QC9Hra7XP5NEQP/8cTMDRCoPurEsLhyc9Lj6fN2MpBrGX4duMAr2+178FF6aldHHTCBv2VmuApTnkguti0Xe+dVxtAqTboFlWYmlt2/c8uBBbW4y2ihe66A4lJsHeU44kfbZbOJBuCe2i+gSdzmWuUXt9MDgiN0R3Ol7TUSrQCBCtI5e7W/tAd4tnC0Us14M7mgurwcwaX/hqe4xWS+/3iuEgXkdhVMQm6p1srqlG0QicwpPxGrAbDOapGjUa///eFzQSXjdKOeCrVa8hyw=="],"ARC-Authentication-Results":["i=2; smtp.subspace.kernel.org;\n dmarc=pass (p=reject dis=none) header.from=de.bosch.com;\n spf=pass smtp.mailfrom=de.bosch.com;\n dkim=pass (2048-bit key) header.d=de.bosch.com header.i=@de.bosch.com\n header.b=Wz6AWPRp; arc=fail smtp.client-ip=40.107.159.53","i=1; mx.microsoft.com 1; spf=pass (sender ip is\n 139.15.153.206) smtp.rcpttodomain=gmail.com smtp.mailfrom=de.bosch.com;\n dmarc=pass (p=reject sp=none pct=100) action=none header.from=de.bosch.com;\n dkim=none (message not signed); arc=none (0)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=de.bosch.com;\n s=selector2;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=YqEzi7YNHEHsRMKBzCrW3g5ZjWsuEVI2+ztfiZbnYDQ=;\n b=Wz6AWPRpdcNL9BrW6jgqE9n5DbRK9Z3tkA14rfh/ZzgALK9zHiJW+GVj7noVYahKtfy9/jKr6zobelrS25Oe355+dlD2QlY0rUecjC5jjqG5G5GhO8Fyhd6HSnKdUO7cCMUIpyos6lHAs+ol61pZVCiT7F4uVKPBiqmAxQJ8dRn5QLtLsjOHWJKOzkvt+iq7URB4qJwfn6+qsiMm/TqaHcwdRBskVJxUzNUAPLBrD5lGyKdhyMk59B08sfF6AoGlRRoVWB6Ola3DrhaKjflJ48V9dPuHV76C088ZrXIXs1sQVTxXj1p8sLXCUpmqAUAC/r0z99/STQmPA7POWeWqNg==","X-MS-Exchange-Authentication-Results":"spf=pass (sender IP is 139.15.153.206)\n smtp.mailfrom=de.bosch.com; dkim=none (message not signed)\n header.d=none;dmarc=pass action=none header.from=de.bosch.com;","Received-SPF":"Pass (protection.outlook.com: domain of de.bosch.com designates\n 139.15.153.206 as permitted sender) receiver=protection.outlook.com;\n client-ip=139.15.153.206; helo=eop.bosch-org.com; pr=C","Message-ID":"<73b1ecdf-8754-4c17-88af-671246a6787d@de.bosch.com>","Date":"Fri, 8 May 2026 07:17:53 +0200","Precedence":"bulk","X-Mailing-List":"linux-pci@vger.kernel.org","List-Id":"<linux-pci.vger.kernel.org>","List-Subscribe":"<mailto:linux-pci+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-pci+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH 01/18] rust: add untrusted data abstraction","To":"<alistair23@gmail.com>, <alistair@alistair23.me>,\n\t<linux-kernel@vger.kernel.org>, <lukas@wunner.de>,\n\t<Jonathan.Cameron@huawei.com>, <bhelgaas@google.com>,\n\t<rust-for-linux@vger.kernel.org>, <akpm@linux-foundation.org>,\n\t<linux-cxl@vger.kernel.org>, <djbw@kernel.org>, <linux-pci@vger.kernel.org>","CC":"<alex.gaynor@gmail.com>, <wilfred.mallawa@wdc.com>, <gary@garyguo.net>,\n\t<bjorn3_gh@protonmail.com>, <benno.lossin@proton.me>, <aliceryhl@google.com>,\n\t<boqun.feng@gmail.com>, <a.hindborg@kernel.org>, <tmgross@umich.edu>,\n\t<ojeda@kernel.org>, Simona Vetter <simona.vetter@ffwll.ch>","References":"<20260508031710.514574-1-alistair.francis@wdc.com>\n <20260508031710.514574-2-alistair.francis@wdc.com>","Content-Language":"en-GB","From":"Dirk Behme <dirk.behme@de.bosch.com>","In-Reply-To":"<20260508031710.514574-2-alistair.francis@wdc.com>","Content-Type":"text/plain; charset=\"UTF-8\"; format=flowed","Content-Transfer-Encoding":"7bit","X-EOPAttributedMessage":"0","X-MS-PublicTrafficType":"Email","X-MS-TrafficTypeDiagnostic":"AM1PEPF000252E1:EE_|AMBPR10MB9928:EE_","X-MS-Office365-Filtering-Correlation-Id":"98343c88-23da-4750-359d-08deacc12c63","X-MS-Exchange-SenderADCheck":"1","X-MS-Exchange-AntiSpam-Relay":"0","X-Microsoft-Antispam":"\n\tBCL:0;ARA:13230040|1800799024|82310400026|7416014|376014|36860700016|921020|13003099007|3023799003|56012099003|18002099003|22082099003;","X-Microsoft-Antispam-Message-Info":"\n\taZ0h5BejfOdnGArr31ZSpu7eVy4rGubZCf8nWumxERuAZAsjbQ0V+DgukOlCxVl4awkYOfaL9RyrSuNaV8egEBc71cG+zcLMiMZ+O+H5sKhCYOa49jVrXT5krtsESbCHUeZA4ogiDx+X3Yqd2lRDl4Hinavaxczs/Y8kUz/MHB5gj33OFJrnzHXUS5gILwFSGR93U6nWK2maGMmxvVLtS7GWpWBr15/V9TJ8hwIX2P+RNsX2mDyB/yhx9uuhr5Kyvj5V4WTT417yr4oIk52JMQLsfsDZNFYBSPzBSvsocJsxMNITQaZ1JHIpJP/k+nMW8pgtgw36iuEzzozjAXCU9qhQg+bX+BaVQBdVqs6US8wFcdn9x7yxRuX0K0H6Uy2TL90RNM+WK81MIN8tfudSGasx2DD3ip8GVEZUUFyZKo2FNOMTlGnwwTHqSxanJnk8uqfHbdeBvm+xDo0So9Cnr58239z37y7ZcZE/cCD0tGPAx5zvVCZKvij5OrLSsS9y4CbYbfo3ax9BhBSIMC0B1beaJdtA5zAwlOnJAnz7ukcB6GuVBiBv6+iMcAJrRW311N4G2uq9Dcs53TvlB6S8HyPckDpCpPncxJFYGbEigQL4BwkAv6ZPEwTtpMiCkM87h4GCutBdL2sDN57v9vQzoF/s0tWRzYQ6XKwtp2B4XpLHw4r29U40gxuK5FGFMF/7kHDPb4Vf6V+NnaiehxhNNcpECsAmDCBzGzuIPy5xypblmkzpJFTbb8A3O6ax1vIov8ONYDzOe8SALKHSo9S87H/So6YnTP5Rj7+wEfrvXAc=","X-Forefront-Antispam-Report":"\n\tCIP:139.15.153.206;CTRY:DE;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:eop.bosch-org.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(1800799024)(82310400026)(7416014)(376014)(36860700016)(921020)(13003099007)(3023799003)(56012099003)(18002099003)(22082099003);DIR:OUT;SFP:1101;","X-MS-Exchange-AntiSpam-MessageData-ChunkCount":"1","X-MS-Exchange-AntiSpam-MessageData-0":"\n\t/+g91y7hroD5AwiGEoxksoOd0PMYKCZARDjciQ1L6I1DNVJ2TiQd9I2oiwJv531WSHVQdbyurjF4t7LMspMvO/AQ/c9wKEk+7xfMbH8Pb0wYzoe75e/o6SykbAPU9lUzkUlvROWQL0C5qd0/r6Y5lm2sXmZEHAmCbYNIA88L5y8OJ8uINCKdpFFLz+bKqyyXYZtxdgw+OFID54yIxuEWHnXDmH/+Ajbg9BOmKRXuJlRYrkACNzx8CQPko5oCbye3iuP+D6Kdru28JI3VMd3pACDFEZBvKv0xcPRE/I6piZ2nobvjBdN4NBQgTKoF4MNhoX9a3YYL4P8vH4kY0hejFO9W+W7TI5st5lkeJkkZ8oT6VxRh2fRQy5bEgVv4gkOcvmhrJtG23wYUBdH/hqRXzPOetUceasR8oCEtvZZRQkfA8lH19OgTBOH4cgMWUxiU","X-OriginatorOrg":"de.bosch.com","X-MS-Exchange-CrossTenant-OriginalArrivalTime":"08 May 2026 05:18:00.5849\n (UTC)","X-MS-Exchange-CrossTenant-Network-Message-Id":"\n 98343c88-23da-4750-359d-08deacc12c63","X-MS-Exchange-CrossTenant-Id":"0ae51e19-07c8-4e4b-bb6d-648ee58410f4","X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp":"\n TenantId=0ae51e19-07c8-4e4b-bb6d-648ee58410f4;Ip=[139.15.153.206];Helo=[eop.bosch-org.com]","X-MS-Exchange-CrossTenant-AuthSource":"\n\tAM1PEPF000252E1.eurprd07.prod.outlook.com","X-MS-Exchange-CrossTenant-AuthAs":"Anonymous","X-MS-Exchange-CrossTenant-FromEntityHeader":"HybridOnPrem","X-MS-Exchange-Transport-CrossTenantHeadersStamped":"AMBPR10MB9928"}}]