From: sashiko-bot@kernel.org
To: "Philipp Stanner" <phasta@kernel.org>
Cc: dri-devel@lists.freedesktop.org, ojeda@kernel.org
Subject: Re: [PATCH v5 4/5] rust: Add dma_fence abstractions
Date: Fri, 03 Jul 2026 07:45:13 +0000 [thread overview]
Message-ID: <20260703074514.9CB5E1F00A3D@smtp.kernel.org> (raw)
In-Reply-To: <20260703073141.3962604-6-phasta@kernel.org>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Lifetime erasure via `ForeignOwnable` or `core::mem::forget` on `DriverFence` leads to a Use-After-Free of `FenceCtx`.
- [Medium] `DriverFence::signal` and `DriverFence::drop` omit the required `dma_fence_begin_signalling()` and `dma_fence_end_signalling()` lockdep annotations.
- [Low] `FenceCbRegistration`'s `# Invariants` documentation is outdated and lacks the mandatory `// INVARIANT:` comment upon construction.
--
commit d72bac0aa1194434de7bc7000b2d5a50bb882d68
Author: Philipp Stanner <phasta@kernel.org>
rust: Add dma_fence abstractions
This commit adds Rust abstractions for the dma_fence subsystem, providing
DriverFence and Fence types to cleanly decouple fence issuers and consumers
while ensuring safe reference counting and signaling.
> diff --git a/rust/kernel/dma_buf/dma_fence.rs b/rust/kernel/dma_buf/dma_fence.rs
> --- /dev/null
> +++ b/rust/kernel/dma_buf/dma_fence.rs
[ ... ]
> +/// # Invariants
> +///
> +/// If callback is Some, then cb is registered with the fence and the
> +/// callback hasn't been invoked yet. If None, the callback has been invoked
> +/// or the fence was already signaled when we tried to register.
> +#[pin_data(PinnedDrop)]
> +pub struct FenceCbRegistration<T: FenceCb + 'static> {
> + #[pin]
> + callback_foreign: Opaque<bindings::dma_fence_cb>,
> + callback: ManuallyDrop<T>,
[Severity: Low]
Is this documentation accurate?
The invariants description references Some and None for the callback
field, but the field is defined as ManuallyDrop<T> rather than an Option.
[ ... ]
> + pub fn new<'a>(fence: &'a Fence, callback: T) -> impl PinInit<Self, CallbackError<T>> + 'a
> + where
> + T: 'a,
> + {
> + try_pin_init!(Self {
> + // We need to fully initialize the fence because after
> + // dma_fence_add_callback() ran, the callback might immediately
> + // get invoked.
> + callback: ManuallyDrop::new(callback),
[Severity: Low]
Are we missing the mandatory INVARIANT comment here?
The Rust subsystem guidelines require an explicit INVARIANT comment when
constructing a struct with an Invariants documentation section, but it
appears to be omitted here.
[ ... ]
> + pub fn signal(self, res: Result) {
> + let fence = self.as_raw();
> + let mut fence_flags: usize = 0;
> + let flag_ptr = &raw mut fence_flags;
> +
> + // SAFETY: fence is valid because self is valid. flag_ptr is
> + // merely a pointer to an integer, which lives as long as this function.
> + unsafe { bindings::dma_fence_lock_irqsave(fence, flag_ptr) };
> + // SAFETY: fence is valid because self is valid. The lock must be
> + // held, which we acquired directly above.
> + if !unsafe { bindings::dma_fence_test_signaled_flag(fence) } {
> + if let Err(err) = res {
> + // SAFETY: fence is valid because self is valid. The fence
> + // must not have been signaled yet, which we check directly above.
> + unsafe { bindings::dma_fence_set_error(fence, err.to_errno()) };
> + }
> + // SAFETY: fence is valid because self is valid. The lock must
> + // be held, which we acquired above.
> + unsafe { bindings::dma_fence_signal_locked(fence) };
> + }
> + // SAFETY: fence is valid because self is valid. flag_ptr is
> + // merely a pointer to an integer, which lives as long as this function.
> + // The lock must be held, which we acquired above.
> + unsafe { bindings::dma_fence_unlock_irqrestore(fence, flag_ptr) };
> + }
[Severity: Medium]
Should this manual signaling path include lockdep annotations?
By open-coding the fence signaling using dma_fence_lock_irqsave() and
dma_fence_signal_locked(), this function omits the
dma_fence_begin_signalling() and dma_fence_end_signalling() calls used in
the equivalent C dma_fence_signal() function.
Without these annotations, lockdep cannot track cross-release dependencies
during fence signaling, which might lead to false negatives when detecting
deadlocks between fence signaling and wait paths.
[ ... ]
> +unsafe impl<'b, T: Send + Sync + FenceCtxOps + 'static> ForeignOwnable for DriverFence<'b, T> {
[Severity: High]
Could this lead to a Use-After-Free if the DriverFence is leaked?
Since DriverFence implements ForeignOwnable without requiring a 'static
lifetime for the 'b parameter, a user can call into_foreign() on a
DriverFence<'a, T> or use core::mem::forget() to leak it.
If the DriverFence is leaked, DriverFence::drop() is never called.
The Rust compiler will then allow the borrowed FenceCtx (tied to
lifetime 'a in DriverFenceData) to be dropped. Once FenceCtx::drop()
completes, the driver_name is freed.
However, the C backend could later interact with the dma_fence, which
is kept alive by ARef<Fence>, and invoke get_driver_name(). This would
dereference the dangling fctx pointer, causing a Use-After-Free.
[ ... ]
> + fn drop(&mut self) {
> + let fence = self.as_raw();
> + let mut fence_flags: usize = 0;
> + let flag_ptr = &raw mut fence_flags;
> +
> + // SAFETY: fence is valid until the call_rcu() below. flag_ptr is
> + // merely a pointer to an integer, which lives as long as this function.
> + unsafe { bindings::dma_fence_lock_irqsave(fence, flag_ptr) };
> +
> + // Use dma_fence_test_signaled_flag() instead of dma_fence_is_signaled_locked()
> + // because the C backend wants to get rid of the latter.
> +
> + // SAFETY: fence is valid until the call_rcu() below.
> + let signaled: bool = unsafe { bindings::dma_fence_test_signaled_flag(fence) };
> + if warn_on!(!signaled) {
> + // SAFETY: fence is valid until the call_rcu() below. The fence
> + // must not have been signaled yet, which we check directly above.
> + unsafe { bindings::dma_fence_set_error(fence, ECANCELED.to_errno()) };
> + // SAFETY: fence is valid until the call_rcu() below. The lock must
> + // be held, which we acquired above.
> + unsafe { bindings::dma_fence_signal_locked(fence) };
> + }
> + // SAFETY: fence is valid until the call_rcu() below. flag_ptr is
> + // merely a pointer to an integer, which lives as long as this function.
> + // The lock must be held, which we acquired above.
> + unsafe { bindings::dma_fence_unlock_irqrestore(fence, flag_ptr) };
[Severity: Medium]
Does this cancellation path also need the lockdep annotations?
Similar to DriverFence::signal(), this open-coded signaling omits the
dma_fence_begin_signalling() and dma_fence_end_signalling() lockdep wrappers,
which prevents cross-release dependency tracking.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260703073141.3962604-2-phasta@kernel.org?part=4
next prev parent reply other threads:[~2026-07-03 7:45 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-03 7:31 [PATCH v5 0/5] rust / dma_buf: Add abstractions for dma_fence Philipp Stanner
2026-07-03 7:31 ` [PATCH v5 1/5] rust: types: implement ForeignOwnable for ARef<T> Philipp Stanner
2026-07-03 7:42 ` sashiko-bot
2026-07-03 7:31 ` [PATCH v5 2/5] rust: error: Add ECANCELED error code Philipp Stanner
2026-07-03 7:31 ` [PATCH v5 3/5] rust: sync: Add abstraction for rcu_barrier() Philipp Stanner
2026-07-03 7:40 ` sashiko-bot
2026-07-03 7:31 ` [PATCH v5 4/5] rust: Add dma_fence abstractions Philipp Stanner
2026-07-03 7:45 ` sashiko-bot [this message]
2026-07-03 7:31 ` [PATCH v5 5/5] MAINTAINERS: Add entry for Rust dma-buf Philipp Stanner
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=20260703074514.9CB5E1F00A3D@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=ojeda@kernel.org \
--cc=phasta@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