From: Philipp Stanner <phasta@mailbox.org>
To: "Philipp Stanner" <phasta@kernel.org>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Sumit Semwal" <sumit.semwal@linaro.org>,
"Christian König" <christian.koenig@amd.com>,
"Paul E. McKenney" <paulmck@kernel.org>,
"Frederic Weisbecker" <frederic@kernel.org>,
"Neeraj Upadhyay" <neeraj.upadhyay@kernel.org>,
"Joel Fernandes" <joelagnelf@nvidia.com>,
"Josh Triplett" <josh@joshtriplett.org>,
"Uladzislau Rezki" <urezki@gmail.com>,
"Steven Rostedt" <rostedt@goodmis.org>,
"Mathieu Desnoyers" <mathieu.desnoyers@efficios.com>,
"Lai Jiangshan" <jiangshanlai@gmail.com>,
Zqiang <qiang.zhang@linux.dev>,
"Daniel Almeida" <daniel.almeida@collabora.com>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Igor Korotin" <igor.korotin@linux.dev>,
"Lorenzo Stoakes" <ljs@kernel.org>,
"Alexandre Courbot" <acourbot@nvidia.com>,
"FUJITA Tomonori" <fujita.tomonori@gmail.com>,
"Krishna Ketan Rai" <prafulrai522@gmail.com>,
"Shankari Anand" <shankari.ak0208@gmail.com>,
manos@pitsidianak.is,
"Boris Brezillon" <boris.brezillon@collabora.com>
Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org,
rcu@vger.kernel.org
Subject: Re: [PATCH v2 5/6] rust: Add dma_fence abstractions
Date: Wed, 17 Jun 2026 11:04:32 +0200 [thread overview]
Message-ID: <e06228542e663bd8020cc91d7646bb7838a3a273.camel@mailbox.org> (raw)
In-Reply-To: <20260616082819.2943886-7-phasta@kernel.org>
On Tue, 2026-06-16 at 10:28 +0200, Philipp Stanner wrote:
>
>
[…]
> Add abstractions for dma_fence in Rust.
>
> Signed-off-by: Philipp Stanner <phasta@kernel.org>
RFC for one thing I'm worried about below
> ---
> rust/bindings/bindings_helper.h | 1 +
> rust/helpers/dma_fence.c | 48 ++
> rust/helpers/helpers.c | 1 +
> rust/kernel/dma_buf/dma_fence.rs | 884 +++++++++++++++++++++++++++++++
> rust/kernel/dma_buf/mod.rs | 14 +
> rust/kernel/lib.rs | 1 +
> 6 files changed, 949 insertions(+)
> create mode 100644 rust/helpers/dma_fence.c
> create mode 100644 rust/kernel/dma_buf/dma_fence.rs
> create mode 100644 rust/kernel/dma_buf/mod.rs
>
>
>
[…]
> +
> +/// The receiving counterpart of a [`DriverFence`], designed to register callbacks
> +/// on, check the signalled state etc. A [`Fence`] cannot be signalled.
> +/// A [`Fence`] is always refcounted.
> +pub struct Fence {
> + /// The actual dma_fence passed to C.
> + inner: Opaque<bindings::dma_fence>,
> +}
> +
>
>
[…]
> +
> +#[repr(C)] // Necessary to guarantee that `inner` always comes first so that we can cast.
> +#[pin_data]
> +struct DriverFenceData<T: Send + Sync + FenceCtxOps> {
> + /// Callback head for dropping this in a deferred manner through RCU.
> + rcu_head: bindings::callback_head,
> + #[pin]
> + /// The inner fence.
> + inner: Fence,
> + /// Pointer to access the FenceCtx. Useful for obtaining name parameters.
> + fctx: Arc<FenceCtx<T>>,
> + /// The API user's data. This must either not need drop, or must delay its
> + /// drop by a grace period. It is essential that the data only performs
> + /// operations legal in atomic context in its [`Drop`] implementation.
> + #[pin]
> + data: T::FenceDataType,
> +}
> +
>
>
>
[…]
> +pub struct DriverFence<T: Send + Sync + FenceCtxOps> {
> + /// The actual content of the fence. Lives in a raw pointer so that its
> + /// memory can be managed independently. Valid until both the [`DriverFence`]
> + /// and all associated [`Fence`]s have disappeared.
> + data: NonNull<DriverFenceData<T>>,
> +}
> +
> +
>
[…]
> }
> +
> +impl<T: Send + Sync + FenceCtxOps> Drop for DriverFence<T> {
> + 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) };
> +
> + // SAFETY: Valid because `self` is valid.
> + let rcu_head_ptr = unsafe { &raw mut (*self.data.as_ptr()).rcu_head };
> +
> + // `DriverFenceData` but could be accessed through some dma_fence callbacks
> + // right now. Access is being revoked in principle above by signalling
> + // the fence, but since the C backend does not guarantee perfect full
> + // synchronization, we have to wait for one grace period to ensure that
> + // all accessors of `DriverFenceData` (through the dma_fence_ops accessible
> + // through a `Fence`) are gone.
> +
> + // SAFETY: `call_rcu()` is always safe to be called. `rcu_head_ptr` was created
> + // validly above. The module must perform a `synchronize_rcu()` or
> + // `rcu_barrier()` call to guard against module unload.
> + unsafe { bindings::call_rcu(rcu_head_ptr, Some(drop_driver_fence_data::<T>)) };
> + }
> +}
> +
> +// TODO:
> +// The entire call_rcu() mechanism in the drop above and the code below would be
> +// unnecessary if C's dma_fence_signal() could be reworked in a way that after it
> +// ran, the caller knows that no fence_ops callbacks can be running anymore.
> +// In other words, if the dma_fence backend would use its spinlock for full
> +// synchronization.
> +//
> +// Then we could move the drop_in_place() and dma_fence_put() upwards into the
> +// drop() implementation and call it a day.
> +
> +/// Finally really drop this `DriverFence<T>`
> +///
> +/// # Safety
> +///
> +/// `head` references the `rcu_head` field of an `DriverFenceData<T>`. All
> +/// accessors to that `DriverFenceData<T>` must be gone by now. This must be
> +/// ensured by signalling the associated `DriverFence<T>` and then waiting
> +/// for a grace period until calling this function here.
> +unsafe extern "C" fn drop_driver_fence_data<T: Send + Sync + FenceCtxOps>(
> + head: *mut bindings::callback_head,
> +) {
> + // SAFETY: Caller provides a pointer to the `rcu_head` field of a `DriverFenceData<C>`.
> + let fence_data = unsafe { container_of!(head, DriverFenceData<T>, rcu_head) };
> +
> + // SAFETY: `fence_data` was created validly above. All the fence's data will
> + // only drop below, but the raw pointer to the raw C `dma_fence` remains
> + // valid because the reference count is only decremented at the end of the
> + // function.
> + let fence = unsafe { (*fence_data).inner.inner.get() };
> +
> + // SAFETY: A grace period has passed. All accessors to that `DriverFenceData`
> + // are gone now. We have exclusive access and can now drop it.
> + unsafe { drop_in_place(fence_data) };
Here we would drop DriverFenceData. We do it like that (RCU delay) now
because of two-fold reasoning:
a) dropping too soon could deallocate the FenceCtx, causing UAF.
b) drop_in_place() invalidates the fctx pointer, so the Rust compiler
could hypothetically write some random data for CPU pipelining etc.
reasons into the pointer, despite it still being used from the backend
functions.
So what I'm wondering about is whether we also solved that problem for
DriverFenceData.inner.inner, i.e., the C dma_fence which resides in
that memory, which can be in use by an arbitrary number of refcounting
Fence's
Does Opaque guarantee that the backing memory within DriverFenceData
will never be interfered with in an undefined behavior way? The
documentation does not explicitly seem to state that.
P.
next prev parent reply other threads:[~2026-06-17 9:04 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-16 8:28 [PATCH v2 0/6] rust / dma_buf: Add abstractions for dma_fence Philipp Stanner
2026-06-16 8:28 ` [PATCH v2 1/6] rust: types: implement ForeignOwnable for ARef<T> Philipp Stanner
2026-06-16 8:28 ` [PATCH v2 2/6] rust: sync: Add abstraction for rcu_barrier() Philipp Stanner
2026-06-16 8:28 ` [PATCH v2 3/6] rust: sync: Add abstraction for synchronize_rcu() Philipp Stanner
2026-06-16 8:28 ` [PATCH v2 4/6] rust: error: Add ECANCELED error code Philipp Stanner
2026-06-16 8:28 ` [PATCH v2 5/6] rust: Add dma_fence abstractions Philipp Stanner
2026-06-16 12:47 ` Onur Özkan
2026-06-16 14:38 ` Philipp Stanner
2026-06-16 14:51 ` Onur Özkan
2026-06-16 15:28 ` Danilo Krummrich
2026-06-16 16:35 ` Onur Özkan
2026-06-16 15:37 ` Gary Guo
2026-06-17 9:04 ` Philipp Stanner [this message]
2026-06-16 8:28 ` [PATCH v2 6/6] MAINTAINERS: Add entry for Rust dma-buf Philipp Stanner
2026-06-16 11:02 ` [PATCH v2 0/6] rust / dma_buf: Add abstractions for dma_fence Danilo Krummrich
2026-06-16 11:28 ` 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=e06228542e663bd8020cc91d7646bb7838a3a273.camel@mailbox.org \
--to=phasta@mailbox.org \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=boris.brezillon@collabora.com \
--cc=christian.koenig@amd.com \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=frederic@kernel.org \
--cc=fujita.tomonori@gmail.com \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=igor.korotin@linux.dev \
--cc=jiangshanlai@gmail.com \
--cc=joelagnelf@nvidia.com \
--cc=josh@joshtriplett.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=ljs@kernel.org \
--cc=lossin@kernel.org \
--cc=manos@pitsidianak.is \
--cc=mathieu.desnoyers@efficios.com \
--cc=neeraj.upadhyay@kernel.org \
--cc=ojeda@kernel.org \
--cc=paulmck@kernel.org \
--cc=phasta@kernel.org \
--cc=prafulrai522@gmail.com \
--cc=qiang.zhang@linux.dev \
--cc=rcu@vger.kernel.org \
--cc=rostedt@goodmis.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=shankari.ak0208@gmail.com \
--cc=sumit.semwal@linaro.org \
--cc=tmgross@umich.edu \
--cc=urezki@gmail.com \
/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
all inboxes | Powered by JetHome®