All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Danilo Krummrich" <dakr@kernel.org>
Cc: ojeda@kernel.org, dri-devel@lists.freedesktop.org,
	"Alexandre Courbot" <acourbot@nvidia.com>
Subject: Re: [PATCH v3 09/13] rust: drm: Add RegistrationGuard for drm_dev_enter/exit critical sections
Date: Sat, 20 Jun 2026 01:12:59 +0000	[thread overview]
Message-ID: <20260620011259.F0B801F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260620005431.1562115-10-dakr@kernel.org>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Device::registration_guard() grants a `Registered` context to unregistered devices, allowing access to unbound hardware.
- [High] RegistrationGuard is implicitly `Send`, causing lockdep splats if dropped on a different thread.
- [Medium] Safe Rust can cause an SRCU deadlock by dropping `Registration` while holding `RegistrationGuard`.
--

commit 3b6c73976ebe0a7066664f9ddc910e85fe1582da
Author: Danilo Krummrich <dakr@kernel.org>

rust: drm: Add RegistrationGuard for drm_dev_enter/exit critical sections

This patch adds RegistrationGuard, a guard object representing a 
drm_dev_enter/exit SRCU critical section. It also changes 
Registration::drop to use drm_dev_unplug() instead of 
drm_dev_unregister() to provide the SRCU barrier required for safety.

> diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs
> index 885077e270ebc..bc8cfd753596e 100644
> --- a/rust/kernel/drm/device.rs
> +++ b/rust/kernel/drm/device.rs

[ ... ]

> @@ -323,6 +321,62 @@ pub(crate) unsafe fn assume_ctx<NewCtx: DeviceContext>(&self) -> &Device<T, NewC
>      }
>  }
>  
> +impl<T: drm::Driver> Device<T> {
> +    /// Guard against the parent bus device being unbound.
> +    ///
> +    /// Returns a [`RegistrationGuard`] if the device has not been unplugged, [`None`] otherwise.
> +    ///
> +    /// While [`RegistrationGuard`] is held the parent device is guaranteed to be bound.
> +    #[must_use]
> +    pub fn registration_guard(&self) -> Option<RegistrationGuard<'_, T>> {
> +        let mut idx: i32 = 0;
> +        // SAFETY: `self.as_raw()` is a valid pointer to a `struct drm_device`.
> +        if unsafe { bindings::drm_dev_enter(self.as_raw(), &mut idx) } {

[Severity: High]
Does this logic correctly prove the device is registered?

Because dev->unplugged defaults to false upon allocation, drm_dev_enter()
will return true for an UnregisteredDevice that has not yet called
drm_dev_register(). 

If device probe fails, the kernel unwinds devres-managed resources but never
creates a Registration or calls drm_dev_unplug(). If an ARef<Device> is
kept alive by a background thread, registration_guard() will still succeed
and return a RegistrationGuard.

This guard dereferences to Device<T, Registered>, which falsely exposes the
parent bus device as bound. Could this lead to a Use-After-Free or invalid
memory access if the parent device's devres-managed hardware resources are
accessed after probe failure? 

Should the guard explicitly verify the registration state (e.g.,
dev->registered) after acquiring the SRCU lock?

> +            Some(RegistrationGuard { dev: self, idx })
> +        } else {
> +            None
> +        }
> +    }
> +}
> +
> +/// A guard proving the DRM device is registered and the parent bus device is bound.
> +///
> +/// The guard dereferences to [`Device<T, Registered>`], providing access to the DRM device with
> +/// the guarantee that the parent bus device is bound for the entire duration of the critical
> +/// section.
> +///
> +/// Internally this is backed by a `drm_dev_enter()` / `drm_dev_exit()` SRCU critical section.
> +///
> +/// # Invariants
> +///
> +/// - `idx` is the SRCU read lock index returned by a successful `drm_dev_enter()` call.
> +/// - The parent bus device of `dev` is bound for the lifetime of this guard.
> +#[must_use]
> +pub struct RegistrationGuard<'a, T: drm::Driver> {
> +    dev: &'a Device<T>,
> +    idx: i32,
> +}

[Severity: High]
Is it intentional that RegistrationGuard is implicitly Send?

Because its inner fields are Send, this allows safe Rust to acquire the
guard on one thread and drop it on another.

While SRCU technically allows cross-thread unlocks, the kernel's lockdep
implementation tracks SRCU read locks per-task. If a guard is dropped on a
different thread, will lockdep emit a bad unlock balance detected splat?

Should RegistrationGuard be explicitly marked !Send (e.g., by adding a
PhantomData<*mut ()> field)?

> +
> +impl<T: drm::Driver> Deref for RegistrationGuard<'_, T> {
> +    type Target = Device<T, Registered>;
> +
> +    #[inline]
> +    fn deref(&self) -> &Self::Target {
> +        // SAFETY: A successful `drm_dev_enter()` guarantees that the device is registered and
> +        // the parent bus device is bound.
> +        unsafe { self.dev.assume_ctx() }

[Severity: High]
Does a successful drm_dev_enter() alone guarantee the Registered state?

As mentioned above, if drm_dev_enter() succeeds on an UnregisteredDevice
after probe failure, this unsafe block will grant the Registered state
incorrectly.

> +    }
> +}

[ ... ]

> diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs
> index 9ba7dc3a7a97a..ceb2829985c78 100644
> --- a/rust/kernel/drm/driver.rs
> +++ b/rust/kernel/drm/driver.rs

[ ... ]

> @@ -199,8 +199,14 @@ unsafe impl<T: Driver> Send for Registration<T> {}
>  
>  impl<T: Driver> Drop for Registration<T> {
>      fn drop(&mut self) {
> +        // Use `drm_dev_unplug` rather than `drm_dev_unregister` to ensure that existing
> +        // `drm_dev_enter()` critical sections complete before unregistration proceeds. This
> +        // is required for the safety of `RegistrationGuard`, which relies on the SRCU barrier in
> +        // `drm_dev_unplug()` to guarantee that the parent device is still bound within the
> +        // critical section.
> +        //
>          // SAFETY: Safe by the invariant of `ARef<drm::Device<T>>`. The existence of this
> -        // `Registration` also guarantees the this `drm::Device` is actually registered.
> -        unsafe { bindings::drm_dev_unregister(self.0.as_raw()) };
> +        // `Registration` also guarantees that this `drm::Device` is actually registered.
> +        unsafe { bindings::drm_dev_unplug(self.0.as_raw()) };

[Severity: Medium]
Can dropping Registration while holding RegistrationGuard on the same
thread cause an SRCU deadlock?

drm_dev_unplug() synchronously waits for all SRCU readers by calling
synchronize_srcu(&drm_unplug_srcu). Since safe Rust can acquire an
independent reference to the device, obtain a RegistrationGuard (which
holds the SRCU read lock), and then drop Registration on the same thread,
synchronize_srcu() could be called from within its own read-side critical
section.

Would this deadlock the thread and trigger an SRCU lockdep warning?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260620005431.1562115-1-dakr@kernel.org?part=9

  reply	other threads:[~2026-06-20  1:13 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-20  0:51 [PATCH v3 00/13] rust: drm: Higher-Ranked Lifetime private data Danilo Krummrich
2026-06-20  0:51 ` [PATCH v3 01/13] rust: drm: rename Uninit DeviceContext to Normal Danilo Krummrich
2026-06-20  0:51 ` [PATCH v3 02/13] rust: drm: Add Driver::ParentDevice associated type Danilo Krummrich
2026-06-20  0:51 ` [PATCH v3 03/13] rust: drm: change default DeviceContext to Normal Danilo Krummrich
2026-06-20  0:51 ` [PATCH v3 04/13] rust: drm: restrict AlwaysRefCounted to Normal Device context Danilo Krummrich
2026-06-20  0:51 ` [PATCH v3 05/13] rust: drm: restrict AlwaysRefCounted to Normal GEM Object context Danilo Krummrich
2026-06-20  0:51 ` [PATCH v3 06/13] rust: drm: split Deref for Device context typestates Danilo Krummrich
2026-06-20  0:51 ` [PATCH v3 07/13] rust: drm: return ParentDevice from Device AsRef Danilo Krummrich
2026-06-20  0:51 ` [PATCH v3 08/13] rust: drm: add AsRef<ParentDevice<Bound>> for Device<Registered> Danilo Krummrich
2026-06-20  0:51 ` [PATCH v3 09/13] rust: drm: Add RegistrationGuard for drm_dev_enter/exit critical sections Danilo Krummrich
2026-06-20  1:12   ` sashiko-bot [this message]
2026-06-20  0:51 ` [PATCH v3 10/13] rust: drm: Add RegistrationData to drm::Driver Danilo Krummrich
2026-06-20  1:10   ` sashiko-bot
2026-06-20  0:51 ` [PATCH v3 11/13] rust: drm: Wrap ioctl dispatch in RegistrationGuard Danilo Krummrich
2026-06-20  1:13   ` sashiko-bot
2026-06-20  0:51 ` [PATCH v3 12/13] rust: drm: Pass registration data to ioctl handlers Danilo Krummrich
2026-06-20  1:16   ` sashiko-bot
2026-06-20  0:51 ` [PATCH v3 13/13] drm: nova: Use drm::Device<Registered> to access the parent bus device Danilo Krummrich
2026-06-20  1:17   ` sashiko-bot
2026-06-20 16:52 ` [PATCH v3 00/13] rust: drm: Higher-Ranked Lifetime private data 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=20260620011259.F0B801F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=dakr@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=ojeda@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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.