Linux Media Controller development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Lyude Paul" <lyude@redhat.com>
Cc: linux-media@vger.kernel.org, ojeda@kernel.org
Subject: Re: [PATCH v15 6/6] rust: drm: gem: Introduce shmem::Object::sg_table()
Date: Sat, 30 May 2026 05:50:27 +0000	[thread overview]
Message-ID: <20260530055027.6B09A1F00893@smtp.kernel.org> (raw)
In-Reply-To: <20260529183702.677677-7-lyude@redhat.com>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Eager evaluation of `Devres::new` and `SGTableMap::new` inside `sg_table()` causes a use-after-free of the scatterlist and leaking of page references.
- [High] Concurrent device unbind and GEM object free causes Use-After-Free of the GEM object in `SGTableMap::drop`.
- [Low] The patch imports and uses `LazyInit`, `new_lazy_init`, and `LazyInitError` from `crate::sync`, but these are neither defined nor exported anywhere in the tree.
--

commit 2d2d3346ec26b2ca8eba7a05f0577c63628921d0
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 494e0d0d8d0d6..5655c2a1ae8fb 100644
> --- a/rust/kernel/drm/gem/shmem.rs
> +++ b/rust/kernel/drm/gem/shmem.rs

[ ... ]

>      sync::{
>          aref::ARef,
>          new_lazy_init,
>          LazyInit,
>          LazyInitError, //
>      },

[Severity: Low]
Are these primitives defined somewhere else?  The patch imports and uses
LazyInit, new_lazy_init, and LazyInitError from crate::sync, but these don't
seem to be present in the tree or introduced anywhere in this patch series.
Will this lead to a module resolution failure and compilation error?

[ ... ]

>      extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) {
>          // SAFETY:
>          // - DRM always passes a valid gem object here
>          // - We used drm_gem_shmem_create() in our create_gem_object callback, so we know that
>          //   `obj` is contained within a drm_gem_shmem_object
>          let base = unsafe { container_of!(obj, bindings::drm_gem_shmem_object, base) };
>  
>          // SAFETY:
>          // - We verified above that `obj` is valid, which makes `this` valid
>          // - This function is set in AllocOps, so we know that `this` is contained within a
>          //   `Object<T>`
>          let this = unsafe { container_of!(Opaque::cast_from(base), Self, obj) }.cast_mut();
>  
>          // We need to reset `sgt_res` first, since doing so requires that the GEM object is still
>          // alive.
>          // SAFETY:
>          // - We verified above that `this` is valid.
>          // - `&mut (*this)` does not implement Unpin.
>          unsafe { Pin::new_unchecked(&mut (*this).sgt_res) }.reset();

[Severity: High]
Does this code introduce a race condition causing a use-after-free?

If drm_gem_object_put() triggers free_callback() concurrently with a device
unbind, the device unbind thread's devres release callback calls
Revocable::revoke().  This swaps is_available to false and blocks on
synchronize_rcu() before dropping SGTableMap.

Concurrently, free_callback() calls sgt_res.reset(), which drops Devres.
Devres::drop() calls revoke_nosync(), which sees is_available is already false
and returns immediately without waiting for the unbind thread.

Then free_callback() proceeds to call drm_gem_shmem_release() and frees the GEM
object memory.

When the unbind thread finishes synchronize_rcu() and executes
SGTableMap::drop(), could it dereference the freed GEM object memory
to lock its dma_resv?

>  
>          // SAFETY:
>          // - We're in free_callback - so this function is safe to call.
>          // - We won't be using the gem resources on `this` after this call.
>          unsafe { bindings::drm_gem_shmem_release(base) };

[ ... ]

>      pub fn sg_table<'a>(
>          &'a self,
>          dev: &'a device::Device<Bound>,
>      ) -> Result<&'a scatterlist::SGTable> {
>          if dev.as_raw() != self.dev().as_ref().as_raw() {
>              return Err(EINVAL);
>          }
>  
>          match self.sgt_res.init(Devres::new(dev, SGTableMap::new(self))) {

[Severity: High]
Can eager evaluation cause a use-after-free and leaked page references here?

In Rust, function arguments are evaluated eagerly.  Devres::new allocates and
executes its initializer eagerly.  SGTableMap::new(self) evaluates its
initializer, causing drm_gem_shmem_get_pages_sgt() to be called synchronously
every time sg_table() is executed, incrementing the page use count.

If sgt_res is already initialized, init() returns LazyInitError::AlreadyInit
and drops the newly created Devres argument.

When Devres is dropped, it drops the inner SGTableMap, calling
SGTableMap::drop(). This calls __drm_gem_shmem_free_sgt_locked(), which
unconditionally unmaps and frees the shared shmem->sgt memory and sets it to
NULL without decrementing the page use count.

Does this leave the originally cached SGTableMap holding a reference to a NULL
or freed shmem->sgt, which would cause a NULL pointer dereference or
use-after-free the next time it's accessed?

>              Ok(ret) | Err(LazyInitError::AlreadyInit(ret)) => Ok(ret.access(dev)?),
>              Err(LazyInitError::DuringInit(e)) => Err(e),
>          }
>      }
>  }

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

      reply	other threads:[~2026-05-30  5:50 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-29 18:33 [PATCH v15 0/6] Rust bindings for gem shmem Lyude Paul
2026-05-29 18:33 ` [PATCH v15 1/6] rust: gem: shmem: Fix Default implementation for ObjectConfig Lyude Paul
2026-05-29 18:46   ` sashiko-bot
2026-05-29 18:34 ` [PATCH v15 2/6] rust: drm: gem/shmem: Add DmaResvGuard helper Lyude Paul
2026-05-29 18:57   ` sashiko-bot
2026-05-29 18:34 ` [PATCH v15 3/6] rust: drm: gem: Add vmap functions to shmem bindings Lyude Paul
2026-05-30  5:06   ` sashiko-bot
2026-05-29 18:34 ` [PATCH v15 4/6] rust: faux: Allow retrieving a bound Device Lyude Paul
2026-05-30  5:14   ` sashiko-bot
2026-05-29 18:34 ` [PATCH v15 5/6] drm/gem/shmem: Introduce __drm_gem_shmem_free_sgt_locked() Lyude Paul
2026-05-30  5:28   ` sashiko-bot
2026-05-29 18:34 ` [PATCH v15 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
2026-05-30  5:50   ` 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=20260530055027.6B09A1F00893@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-media@vger.kernel.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox