All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Lyude Paul" <lyude@redhat.com>
Cc: ojeda@kernel.org, dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v20 4/4] rust: drm: gem: Introduce shmem::Object::sg_table()
Date: Wed, 10 Jun 2026 16:46:21 +0000	[thread overview]
Message-ID: <20260610164622.6A5AB1F00893@smtp.kernel.org> (raw)
In-Reply-To: <20260610162433.923550-5-lyude@redhat.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] A concurrent device unbind and GEM object destruction results in a use-after-free and double-free when SGTableMap::drop accesses the freed GEM object.
- [High] SGTableMap::drop unconditionally calls __drm_gem_shmem_free_sgt_locked(), causing NULL pointer dereferences for purged objects, memory corruption for PRIME-imported objects, and leaked page references.
--

commit 8c8b7df9b9589f955da172bd30324598c3ed5764
Author: Lyude Paul <lyude@redhat.com>

rust: drm: gem: Introduce shmem::Object::sg_table()
    
In order to do this, we need to be careful to ensure that any interface we
expose for scatterlists ensures that any mappings created from one are
destroyed on driver-unbind. To do this, we introduce a Devres resource into
shmem::Object that we use in order to ensure that we release any SGTable
mappings on driver-unbind.

> diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs
> index d4afc06d1be50..f44665cc24119 100644
> --- a/rust/kernel/drm/gem/shmem.rs
> +++ b/rust/kernel/drm/gem/shmem.rs

[ ... ]

> @@ -488,6 +560,64 @@ unsafe fn io_write(&self, value: $ty, address: usize) {
>  #[cfg(CONFIG_64BIT)]
>  impl_vmap_io_capable!(u64);
>  
> +/// A reference to a GEM object that is known to have a mapped [`SGTable`].
> +///
> +/// This is used by the Rust bindings with [`Devres`] in order to ensure that mappings for SGTables
> +/// on GEM shmem objects are revoked on driver-unbind.
> +///
> +/// # Invariants
> +///
> +/// - `self.obj` always points to a valid GEM object.
> +/// - This object is proof that `self.obj.owner.sgt_res` has an initialized and valid pointer to an
> +///   [`SGTable`].
> +///
> +/// [`SGTable`]: scatterlist::SGTable
> +pub struct SGTableMap<T: DriverObject, C: DeviceContext> {
> +    obj: NonNull<Object<T, C>>,
> +}
> +
> +impl<T: DriverObject, C: DeviceContext> Deref for SGTableMap<T, C> {
> +    type Target = scatterlist::SGTable;
> +
> +    fn deref(&self) -> &Self::Target {
> +        // SAFETY:
> +        // - The NonNull is guaranteed to be valid via our type invariants.
> +        // - The sgt field is guaranteed to be initialized and valid via our type invariants.
> +        unsafe { scatterlist::SGTable::from_raw((*self.obj.as_ref().as_raw_shmem()).sgt) }
> +    }
> +}
> +
> +impl<T: DriverObject, C: DeviceContext> Drop for SGTableMap<T, C> {
> +    fn drop(&mut self) {
> +        // SAFETY: `obj` is always valid via our type invariants
> +        let obj = unsafe { self.obj.as_ref() };
> +        let _lock = DmaResvGuard::new(obj);

[Severity: Critical]
Can a concurrent device unbind and GEM object destruction result in a
use-after-free here?

When a GEM object's final reference is dropped, free_callback() is executed
and it drops the SetOnce wrapper:

    unsafe { ManuallyDrop::drop(&mut (*this).sgt_res) };

This invokes Devres::drop(), which calls revoke_nosync().

If the device is concurrently unbound, the devres unbind thread will call
revoke() on the Devres object, setting its availability flag to false and
waiting via synchronize_rcu() before dropping SGTableMap.

Because revoke_nosync() on the free_callback thread sees the flag is already
false, it returns immediately without synchronizing. free_callback() then
proceeds to free the GEM object memory via drm_gem_shmem_release().

Once synchronize_rcu() finishes in the unbind thread, this SGTableMap::drop
runs and dereferences the now-freed self.obj pointer, resulting in a
use-after-free.

> +
> +        // SAFETY: We acquired the lock needed for calling this function above
> +        unsafe { bindings::__drm_gem_shmem_free_sgt_locked(obj.as_raw_shmem()) };

[Severity: High]
Does unconditionally calling __drm_gem_shmem_free_sgt_locked() handle purged
or PRIME-imported objects correctly?

If a Rust Object is PRIME-imported, shmem->sgt points to an SGT owned by the
exporting driver, and calling this could free and corrupt the exporter's
memory.

Additionally, if the object was purged by the shrinker, shmem->sgt is freed
and set to NULL. Calling __drm_gem_shmem_free_sgt_locked() does not check
for NULL, which could lead to a NULL pointer dereference in
dma_unmap_sgtable().

Finally, for native objects, drm_gem_shmem_get_pages_sgt() pins the pages
and increments pages_use_count. By only freeing the SGT and skipping the
required drm_gem_shmem_put_pages_locked() call, does this leak page
references until the object's file descriptor is closed?

> +    }
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260610162433.923550-1-lyude@redhat.com?part=4

      reply	other threads:[~2026-06-10 16:46 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-10 16:21 [PATCH v20 0/4] Rust bindings for gem shmem Lyude Paul
2026-06-10 16:21 ` Lyude Paul
2026-06-10 16:21 ` [PATCH v20 1/4] rust: drm: gem: shmem: Add DmaResvGuard helper Lyude Paul
2026-06-10 16:21   ` Lyude Paul
2026-06-10 16:21 ` [PATCH v20 2/4] rust: drm: gem: shmem: Add vmap functions Lyude Paul
2026-06-10 16:21   ` Lyude Paul
2026-06-10 16:39   ` sashiko-bot
2026-06-10 16:21 ` [PATCH v20 3/4] rust: faux: Allow retrieving a bound Device Lyude Paul
2026-06-10 16:21   ` Lyude Paul
2026-06-10 16:37   ` sashiko-bot
2026-06-10 16:21 ` [PATCH v20 4/4] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
2026-06-10 16:21   ` Lyude Paul
2026-06-10 16:46   ` sashiko-bot [this message]

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=20260610164622.6A5AB1F00893@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=lyude@redhat.com \
    --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.