From: sashiko-bot@kernel.org
To: "Lyude Paul" <lyude@redhat.com>
Cc: ojeda@kernel.org, linux-media@vger.kernel.org
Subject: Re: [PATCH v17 6/6] rust: drm: gem: Introduce shmem::Object::sg_table()
Date: Wed, 03 Jun 2026 20:12:06 +0000 [thread overview]
Message-ID: <20260603201206.C95721F00893@smtp.kernel.org> (raw)
In-Reply-To: <20260603195210.693856-7-lyude@redhat.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] `SGTableMap::drop` unconditionally frees the scatter/gather table, which corrupts memory for imported dma-buf GEM objects.
- [Critical] Concurrent device unbind and GEM object destruction causes a Use-After-Free of the GEM object and its dma_resv lock in `SGTableMap::drop`.
- [High] `SGTableMap` fails to pin the shmem GEM object backing pages, exposing the SG table to being purged by the shrinker and causing a NULL pointer dereference. It also leaks the `pages_use_count` on drop.
--
commit 8870abbe2654a7715fcd51335a14b62f57e22680
Author: Lyude Paul <lyude@redhat.com>
rust: drm: gem: Introduce shmem::Object::sg_table()
This commit introduces a Devres-managed SGTableMap to ensure that
scatterlist mappings for GEM shmem objects are released upon driver
unbind. It adds the sg_table() method to shmem::Object which is intended
to pin the object and return its scatter/gather table.
> diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs
> index 1f05a5bc5fe66..dff90771eb34a 100644
> --- a/rust/kernel/drm/gem/shmem.rs
> +++ b/rust/kernel/drm/gem/shmem.rs
[ ... ]
> @@ -189,18 +210,25 @@ extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) {
> // - 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 this = unsafe { container_of!(obj, bindings::drm_gem_shmem_object, base) };
> -
> - // 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(this) };
> + 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, C>`
> - let this = unsafe { container_of!(Opaque::cast_from(this), Self, obj) }.cast_mut();
> + let this = unsafe { container_of!(Opaque::cast_from(base), Self, obj) }.cast_mut();
> +
> + // We need to drop `sgt_res` first, since doing so requires that the GEM object is still
> + // alive.
> + // SAFETY:
> + // - We verified above that `this` is valid.
> + // - We are in free_callback, guaranteeing we have exclusive access to `this`.
> + unsafe { &mut (*this).sgt_res }.reset();
[Severity: Critical]
Does this leave a window for a use-after-free if the device unbinds
concurrently?
If the devres subsystem is already running SGTableMap::drop() in another
thread during device unbind, sgt_res.reset() could silently fail to remove
the action. The callback would then proceed to free the GEM object while
SGTableMap::drop() is still dereferencing and locking it.
> +
> + // 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) };
[ ... ]
> +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);
> +
> + // SAFETY: We acquired the lock needed for calling this function above
> + unsafe { bindings::__drm_gem_shmem_free_sgt_locked(obj.as_raw_shmem()) };
[Severity: Critical]
Is it safe to unconditionally free the scatter/gather table here?
If the GEM object was imported from a dma-buf, the scatter/gather table
belongs to the exporter. Calling __drm_gem_shmem_free_sgt_locked() directly
without checking drm_gem_is_imported() seems like it might illegally free
the exporter's memory.
[Severity: High]
Could this drop implementation also leak the pages_use_count?
Calling __drm_gem_shmem_free_sgt_locked() alone doesn't seem to drop the
page use count acquired during SGTableMap::new(). Should this also call
drm_gem_shmem_put_pages_locked() to balance the counts?
> + }
> +}
> +
> +impl<T: DriverObject, C: DeviceContext> SGTableMap<T, C> {
> + fn new(obj: &Object<T, C>) -> impl Init<Self, Error> {
> + // INVARIANT:
> + // - We call drm_gem_shmem_get_pages_sgt_locked below and check whether or not it
> + // succeeds, fulfilling the invariant of SGTableMap that the object's `sgt` field is
> + // initialized.
> + // SAFETY:
> + // - `obj` is fully initialized, making this function safe to call.
> + from_err_ptr(unsafe { bindings::drm_gem_shmem_get_pages_sgt(obj.as_raw_shmem()) })?;
[Severity: High]
Does this expose the object to being purged by the DRM LRU shrinker?
The Object::sg_table() documentation mentions this will pin the object in
memory, but drm_gem_shmem_get_pages_sgt() only increments the
pages_use_count, not the pages_pin_count. If userspace marks the object as
MADV_DONTNEED, the shrinker could purge it and set shmem->sgt to NULL.
Could this lead to a NULL pointer dereference later in SGTableMap::drop()
when it passes the pointer to __drm_gem_shmem_free_sgt_locked()?
> +
> + Ok(Self { obj: obj.into() })
> + }
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260603195210.693856-1-lyude@redhat.com?part=6
prev parent reply other threads:[~2026-06-03 20:12 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-03 19:42 [PATCH v17 0/6] Rust bindings for gem shmem Lyude Paul
2026-06-03 19:42 ` [PATCH v17 1/6] rust: drm: gem: shmem: Fix Default implementation for ObjectConfig Lyude Paul
2026-06-03 20:02 ` sashiko-bot
2026-06-04 11:49 ` Alice Ryhl
2026-06-03 19:42 ` [PATCH v17 2/6] rust: drm: gem: shmem: Add DmaResvGuard helper Lyude Paul
2026-06-03 20:09 ` sashiko-bot
2026-06-03 19:42 ` [PATCH v17 3/6] rust: drm: gem: shmem: Add vmap functions Lyude Paul
2026-06-03 20:11 ` sashiko-bot
2026-06-03 19:42 ` [PATCH v17 4/6] rust: faux: Allow retrieving a bound Device Lyude Paul
2026-06-03 20:08 ` sashiko-bot
2026-06-04 13:25 ` Danilo Krummrich
2026-06-04 18:48 ` lyude
2026-06-03 19:42 ` [PATCH v17 5/6] rust: sync: Add SetOnce::reset() Lyude Paul
2026-06-03 20:07 ` sashiko-bot
2026-06-04 11:58 ` Alice Ryhl
2026-06-04 18:53 ` lyude
2026-06-03 19:42 ` [PATCH v17 6/6] rust: drm: gem: Introduce shmem::Object::sg_table() Lyude Paul
2026-06-03 20:12 ` 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=20260603201206.C95721F00893@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