From: "Gary Guo" <gary@garyguo.net>
To: "Danilo Krummrich" <dakr@kernel.org>,
<gregkh@linuxfoundation.org>, <rafael@kernel.org>,
<acourbot@nvidia.com>, <aliceryhl@google.com>,
<david.m.ertman@intel.com>, <ira.weiny@intel.com>,
<leon@kernel.org>, <viresh.kumar@linaro.org>,
<m.wilczynski@samsung.com>, <ukleinek@kernel.org>,
<bhelgaas@google.com>, <kwilczynski@kernel.org>,
<abdiel.janulgue@gmail.com>, <robin.murphy@arm.com>,
<markus.probst@posteo.de>, <ojeda@kernel.org>, <boqun@kernel.org>,
<gary@garyguo.net>, <bjorn3_gh@protonmail.com>,
<lossin@kernel.org>, <a.hindborg@kernel.org>, <tmgross@umich.edu>,
<igor.korotin@linux.dev>, <daniel.almeida@collabora.com>,
<pcolberg@redhat.com>
Cc: <driver-core@lists.linux.dev>, <linux-kernel@vger.kernel.org>,
<nova-gpu@lists.linux.dev>, <dri-devel@lists.freedesktop.org>,
<linux-pm@vger.kernel.org>, <linux-pwm@vger.kernel.org>,
<linux-pci@vger.kernel.org>, <rust-for-linux@vger.kernel.org>,
"Eliot Courtney" <ecourtney@nvidia.com>
Subject: Re: [PATCH v5 23/24] rust: auxiliary: generalize Registration over ForLt
Date: Wed, 27 May 2026 14:55:12 +0100 [thread overview]
Message-ID: <DITIDXOEZ54S.2PU9VU9UGTSZP@garyguo.net> (raw)
In-Reply-To: <20260525202921.124698-24-dakr@kernel.org>
On Mon May 25, 2026 at 9:21 PM BST, Danilo Krummrich wrote:
> Generalize Registration<T> to Registration<F: ForLt> and
> Device::registration_data<F: ForLt>() to return Pin<&F::Of<'_>>.
>
> The stored 'static lifetime is shortened to the borrow lifetime of &self
> via ForLt::cast_ref; ForLt's covariance guarantee makes this sound.
>
> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
> Reviewed-by: Eliot Courtney <ecourtney@nvidia.com>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
> drivers/gpu/nova-core/driver.rs | 13 ++--
> rust/kernel/auxiliary.rs | 108 +++++++++++++++++++-------
> samples/rust/rust_driver_auxiliary.rs | 19 +++--
> 3 files changed, 96 insertions(+), 44 deletions(-)
>
> diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
> index fa898fe5c893..d3f2245ba2e0 100644
> --- a/drivers/gpu/nova-core/driver.rs
> +++ b/drivers/gpu/nova-core/driver.rs
> @@ -3,7 +3,6 @@
> use kernel::{
> auxiliary,
> device::Core,
> - devres::Devres,
> dma::Device,
> dma::DmaMask,
> pci,
> @@ -21,6 +20,7 @@
> },
> Arc,
> },
> + types::ForLt,
> };
>
> use crate::gpu::Gpu;
> @@ -29,10 +29,11 @@
> static AUXILIARY_ID_COUNTER: Atomic<u32> = Atomic::new(0);
>
> #[pin_data]
> -pub(crate) struct NovaCore {
> +pub(crate) struct NovaCore<'bound> {
> #[pin]
> pub(crate) gpu: Gpu,
> - _reg: Devres<auxiliary::Registration<()>>,
> + #[allow(clippy::type_complexity)]
> + _reg: auxiliary::Registration<'bound, ForLt!(())>,
> }
>
> pub(crate) struct NovaCoreDriver;
> @@ -76,13 +77,13 @@ pub(crate) struct NovaCore {
>
> impl pci::Driver for NovaCoreDriver {
> type IdInfo = ();
> - type Data<'bound> = NovaCore;
> + type Data<'bound> = NovaCore<'bound>;
> const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
>
> fn probe<'bound>(
> pdev: &'bound pci::Device<Core<'_>>,
> _info: &'bound Self::IdInfo,
> - ) -> impl PinInit<NovaCore, Error> + 'bound {
> + ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
> pin_init::pin_init_scope(move || {
> dev_dbg!(pdev, "Probe Nova Core GPU driver.\n");
>
> @@ -115,7 +116,7 @@ fn probe<'bound>(
> })
> }
>
> - fn unbind<'bound>(pdev: &'bound pci::Device<Core<'_>>, this: Pin<&NovaCore>) {
> + fn unbind<'bound>(pdev: &'bound pci::Device<Core<'_>>, this: Pin<&Self::Data<'bound>>) {
> this.gpu.unbind(pdev.as_ref());
> }
> }
> diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
> index 7a1b1a7b7ca6..75ddb0220748 100644
> --- a/rust/kernel/auxiliary.rs
> +++ b/rust/kernel/auxiliary.rs
> @@ -12,7 +12,7 @@
> RawDeviceId,
> RawDeviceIdIndex, //
> },
> - devres::Devres,
> +
> driver,
> error::{
> from_result,
> @@ -20,6 +20,7 @@
> },
> prelude::*,
> types::{
> + ForLt,
> ForeignOwnable,
> Opaque, //
> },
> @@ -271,12 +272,16 @@ pub fn parent(&self) -> &device::Device<device::Bound> {
>
> /// Returns a pinned reference to the registration data set by the registering (parent) driver.
> ///
> - /// Returns [`EINVAL`] if `T` does not match the type used by the parent driver when calling
> + /// `F` is the [`ForLt`](trait@ForLt) encoding of the data type. The returned
> + /// reference has its lifetime shortened from `'static` to `&self`'s borrow lifetime via
> + /// [`ForLt::cast_ref`].
> + ///
> + /// Returns [`EINVAL`] if `F` does not match the type used by the parent driver when calling
> /// [`Registration::new()`].
> ///
> /// Returns [`ENOENT`] if no registration data has been set, e.g. when the device was
> /// registered by a C driver.
> - pub fn registration_data<T: 'static>(&self) -> Result<Pin<&T>> {
> + pub fn registration_data<F: ForLt + 'static>(&self) -> Result<Pin<&F::Of<'_>>> {
> // SAFETY: By the type invariant, `self.as_raw()` is a valid `struct auxiliary_device`.
> let ptr = unsafe { (*self.as_raw()).registration_data_rust };
> if ptr.is_null() {
> @@ -289,18 +294,23 @@ pub fn registration_data<T: 'static>(&self) -> Result<Pin<&T>> {
>
> // SAFETY: `ptr` is non-null and was set via `into_foreign()` in `Registration::new()`;
> // `RegistrationData` is `#[repr(C)]` with `type_id` at offset 0, so reading a `TypeId`
> - // at the start of the allocation is valid regardless of `T`.
> + // at the start of the allocation is valid regardless of `F`.
> let type_id = unsafe { ptr.cast::<TypeId>().read() };
> - if type_id != TypeId::of::<T>() {
> + if type_id != TypeId::of::<F>() {
> return Err(EINVAL);
> }
>
> - // SAFETY: The `TypeId` check above confirms that the stored type is `T`; `ptr` remains
> - // valid until `Registration::drop()` calls `from_foreign()`.
> - let wrapper = unsafe { Pin::<KBox<RegistrationData<T>>>::borrow(ptr) };
> + // SAFETY: The `TypeId` check above confirms that the stored type matches
> + // `F::Of<'static>`; `ptr` remains valid until `Registration::drop()` calls
> + // `from_foreign()`.
> + let wrapper = unsafe { Pin::<KBox<RegistrationData<F::Of<'static>>>>::borrow(ptr) };
>
> // SAFETY: `data` is a structurally pinned field of `RegistrationData`.
> - Ok(unsafe { wrapper.map_unchecked(|w| &w.data) })
> + let pinned: Pin<&F::Of<'static>> = unsafe { wrapper.map_unchecked(|w| &w.data) };
I think `'_` is sufficient here?
> +
> + // SAFETY: The data was pinned when stored; `cast_ref` only shortens
> + // the lifetime, so the pinning guarantee is preserved.
> + Ok(unsafe { Pin::new_unchecked(F::cast_ref(pinned.get_ref())) })
> }
> }
>
> @@ -389,43 +399,61 @@ struct RegistrationData<T> {
> /// This type represents the registration of a [`struct auxiliary_device`]. When its parent device
> /// is unbound, the corresponding auxiliary device will be unregistered from the system.
> ///
> -/// The type parameter `T` is the type of the registration data owned by the registering (parent)
> -/// driver. It can be accessed by the auxiliary driver through
> -/// [`Device::registration_data()`].
> +/// The type parameter `F` is a [`ForLt`](trait@ForLt) encoding of the registration
> +/// data type. For non-lifetime-parameterized types, use [`ForLt!(T)`](macro@ForLt).
> +/// The data can be accessed by the auxiliary driver through [`Device::registration_data()`].
> ///
> /// # Invariants
> ///
> /// `self.adev` always holds a valid pointer to an initialized and registered
> /// [`struct auxiliary_device`] whose `registration_data_rust` field points to a
> -/// valid `Pin<KBox<RegistrationData<T>>>`.
> -pub struct Registration<T: 'static> {
> +/// valid `Pin<KBox<RegistrationData<F::Of<'static>>>>`.
> +pub struct Registration<'a, F: ForLt + 'static> {
> adev: NonNull<bindings::auxiliary_device>,
> - _data: PhantomData<T>,
> + #[allow(clippy::type_complexity)]
Is this acutally needed?
> + _phantom: PhantomData<(fn(&'a ()) -> &'a (), F)>,
Could you update this to `PhantomData<F::Of<'a>>` please? It matches better
what's is actually being stored.
'a also does not actually need to be invariant here if `F::Of` is covariant
(which currently `ForLt` guarantees). (Although, lifetimes will still be
invariant as it's used in assoc type by changing to `F::Of<'a>`). Variance of
`'a` is not what matters here; the covariance of `F::Of` is load-bearing part
for the `registration_data` method, and the !Leak requirement is the
load-bearing part for UAF protection.
Feel free to add my R-b with the change.
Best,
Gary
> }
>
> -impl<T: Send + Sync + 'static> Registration<T> {
> +impl<'a, F: ForLt> Registration<'a, F>
> +where
> + for<'b> F::Of<'b>: Send + Sync,
> +{
> /// Create and register a new auxiliary device with the given registration data.
> ///
> /// The `data` is owned by the registration and can be accessed through the auxiliary device
> /// via [`Device::registration_data()`].
> - pub fn new<E>(
> - parent: &device::Device<device::Bound>,
> + ///
> + /// # Safety
> + ///
> + /// The caller must not `mem::forget()` the returned [`Registration`] or otherwise prevent its
> + /// [`Drop`] implementation from running, since the registration data may contain borrowed
> + /// references that become invalid after `'a` ends.
> + ///
> + /// If the registration data is `'static`, use the safe [`Registration::new()`] instead.
> + pub unsafe fn new_with_lt<E>(
> + parent: &'a device::Device<device::Bound>,
> name: &CStr,
> id: u32,
> modname: &CStr,
> - data: impl PinInit<T, E>,
> - ) -> Result<Devres<Self>>
> + data: impl PinInit<F::Of<'a>, E>,
> + ) -> Result<Self>
> where
> Error: From<E>,
> {
> let data = KBox::pin_init::<Error>(
> try_pin_init!(RegistrationData {
> - type_id: TypeId::of::<T>(),
> + type_id: TypeId::of::<F>(),
> data <- data,
> }),
> GFP_KERNEL,
> )?;
>
> + // SAFETY: `'a` is invariant (via `Registration`'s `PhantomData`). Lifetimes do not
> + // affect layout, so RegistrationData<F::Of<'a>> and RegistrationData<F::Of<'static>>
> + // have identical representation.
> + let data: Pin<KBox<RegistrationData<F::Of<'static>>>> =
> + unsafe { core::mem::transmute(data) };
> +
> let boxed: KBox<Opaque<bindings::auxiliary_device>> = KBox::zeroed(GFP_KERNEL)?;
> let adev = boxed.get();
>
> @@ -455,7 +483,9 @@ pub fn new<E>(
> if ret != 0 {
> // SAFETY: `registration_data` was set above via `into_foreign()`.
> drop(unsafe {
> - Pin::<KBox<RegistrationData<T>>>::from_foreign((*adev).registration_data_rust)
> + Pin::<KBox<RegistrationData<F::Of<'static>>>>::from_foreign(
> + (*adev).registration_data_rust,
> + )If it's un
> });
>
> // SAFETY: `adev` is guaranteed to be a valid pointer to a
> @@ -467,18 +497,36 @@ pub fn new<E>(
>
> // INVARIANT: The device will remain registered until `auxiliary_device_delete()` is
> // called, which happens in `Self::drop()`.
> - let reg = Self {
> + Ok(Self {
> // SAFETY: `adev` is guaranteed to be non-null, since the `KBox` was allocated
> // successfully.
> adev: unsafe { NonNull::new_unchecked(adev) },
> - _data: PhantomData,
> - };
> + _phantom: PhantomData,
> + })
> + }
>
> - Devres::new::<core::convert::Infallible>(parent, reg)
> + /// Create and register a new auxiliary device with `'static` registration data.
> + ///
> + /// Safe variant of [`Registration::new_with_lt()`] for registration data that does not contain
> + /// borrowed references.
> + pub fn new<E>(
> + parent: &'a device::Device<device::Bound>,
> + name: &CStr,
> + id: u32,
> + modname: &CStr,
> + data: impl PinInit<F::Of<'a>, E>,
> + ) -> Result<Self>
> + where
> + F::Of<'a>: 'static,
> + Error: From<E>,
> + {
> + // SAFETY: `F::Of<'a>: 'static` guarantees the data contains no borrowed references,
> + // so forgetting the `Registration` cannot cause use-after-free.
> + unsafe { Self::new_with_lt(parent, name, id, modname, data) }
> }
> }
next prev parent reply other threads:[~2026-05-27 13:55 UTC|newest]
Thread overview: 55+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-25 20:20 [PATCH v5 00/24] rust: device: Higher-Ranked Lifetime Types for device drivers Danilo Krummrich
2026-05-25 20:20 ` [PATCH v5 01/24] rust: pci: use 'static lifetime for PCI BAR resource names Danilo Krummrich
2026-05-25 21:02 ` sashiko-bot
2026-05-26 0:38 ` Eliot Courtney
2026-05-26 2:22 ` Alexandre Courbot
2026-05-27 11:58 ` Gary Guo
2026-05-25 20:20 ` [PATCH v5 02/24] rust: alloc: remove `'static` bound on `ForeignOwnable` Danilo Krummrich
2026-05-26 18:21 ` Miguel Ojeda
2026-05-25 20:20 ` [PATCH v5 03/24] rust: driver: move 'static bounds to constructor Danilo Krummrich
2026-05-25 20:20 ` [PATCH v5 04/24] rust: driver: decouple driver private data from driver type Danilo Krummrich
2026-05-25 20:47 ` sashiko-bot
2026-05-25 20:20 ` [PATCH v5 05/24] rust: driver core: drop drvdata before devres release Danilo Krummrich
2026-05-25 21:03 ` sashiko-bot
2026-05-25 20:20 ` [PATCH v5 06/24] rust: pci: implement Sync for Device<Bound> Danilo Krummrich
2026-05-25 20:20 ` [PATCH v5 07/24] rust: platform: " Danilo Krummrich
2026-05-25 21:33 ` sashiko-bot
2026-05-25 20:20 ` [PATCH v5 08/24] rust: auxiliary: " Danilo Krummrich
2026-05-25 20:20 ` [PATCH v5 09/24] rust: usb: " Danilo Krummrich
2026-05-25 21:15 ` sashiko-bot
2026-05-25 20:20 ` [PATCH v5 10/24] rust: device: " Danilo Krummrich
2026-05-25 20:20 ` [PATCH v5 11/24] rust: device: make Core and CoreInternal lifetime-parameterized Danilo Krummrich
2026-05-27 13:13 ` Gary Guo
2026-05-25 20:20 ` [PATCH v5 12/24] rust: pci: make Driver trait lifetime-parameterized Danilo Krummrich
2026-05-27 13:21 ` Gary Guo
2026-05-25 20:21 ` [PATCH v5 13/24] rust: platform: " Danilo Krummrich
2026-05-27 13:22 ` Gary Guo
2026-05-25 20:21 ` [PATCH v5 14/24] rust: auxiliary: " Danilo Krummrich
2026-05-27 13:22 ` Gary Guo
2026-05-25 20:21 ` [PATCH v5 15/24] rust: usb: " Danilo Krummrich
2026-05-25 21:14 ` sashiko-bot
2026-05-27 13:22 ` Gary Guo
2026-05-27 13:38 ` Daniel Almeida
2026-05-25 20:21 ` [PATCH v5 16/24] rust: i2c: " Danilo Krummrich
2026-05-25 21:12 ` sashiko-bot
2026-05-27 13:23 ` Gary Guo
2026-05-25 20:21 ` [PATCH v5 17/24] rust: driver: update module documentation for GAT-based Data type Danilo Krummrich
2026-05-27 13:24 ` Gary Guo
2026-05-25 20:21 ` [PATCH v5 18/24] rust: pci: make Bar lifetime-parameterized Danilo Krummrich
2026-05-27 13:30 ` Gary Guo
2026-05-25 20:21 ` [PATCH v5 19/24] rust: io: make IoMem and ExclusiveIoMem lifetime-parameterized Danilo Krummrich
2026-05-25 21:44 ` sashiko-bot
2026-05-27 13:31 ` Gary Guo
2026-05-25 20:21 ` [PATCH v5 20/24] samples: rust: rust_driver_pci: use HRT lifetime for Bar Danilo Krummrich
2026-05-27 13:41 ` Gary Guo
2026-05-25 20:21 ` [PATCH v5 21/24] gpu: nova-core: separate driver type from driver data Danilo Krummrich
2026-05-27 13:39 ` Gary Guo
2026-05-25 20:21 ` [PATCH v5 22/24] rust: types: add `ForLt` trait for higher-ranked lifetime support Danilo Krummrich
2026-05-25 21:20 ` sashiko-bot
2026-05-26 5:44 ` Alexandre Courbot
2026-05-26 18:49 ` Miguel Ojeda
2026-05-25 20:21 ` [PATCH v5 23/24] rust: auxiliary: generalize Registration over ForLt Danilo Krummrich
2026-05-27 13:55 ` Gary Guo [this message]
2026-05-25 20:21 ` [PATCH v5 24/24] samples: rust: rust_driver_auxiliary: showcase lifetime-bound registration data Danilo Krummrich
2026-05-25 21:24 ` sashiko-bot
2026-05-27 21:24 ` [PATCH v5 00/24] rust: device: Higher-Ranked Lifetime Types for device drivers Danilo Krummrich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=DITIDXOEZ54S.2PU9VU9UGTSZP@garyguo.net \
--to=gary@garyguo.net \
--cc=a.hindborg@kernel.org \
--cc=abdiel.janulgue@gmail.com \
--cc=acourbot@nvidia.com \
--cc=aliceryhl@google.com \
--cc=bhelgaas@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=david.m.ertman@intel.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=driver-core@lists.linux.dev \
--cc=ecourtney@nvidia.com \
--cc=gregkh@linuxfoundation.org \
--cc=igor.korotin@linux.dev \
--cc=ira.weiny@intel.com \
--cc=kwilczynski@kernel.org \
--cc=leon@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=linux-pwm@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=m.wilczynski@samsung.com \
--cc=markus.probst@posteo.de \
--cc=nova-gpu@lists.linux.dev \
--cc=ojeda@kernel.org \
--cc=pcolberg@redhat.com \
--cc=rafael@kernel.org \
--cc=robin.murphy@arm.com \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
--cc=ukleinek@kernel.org \
--cc=viresh.kumar@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.