All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alice Ryhl <aliceryhl@google.com>
To: phasta@kernel.org
Cc: sashiko-reviews@lists.linux.dev, linux-media@vger.kernel.org,
	 ojeda@kernel.org,
	Boris Brezillon <boris.brezillon@collabora.com>
Subject: Re: [PATCH 3/4] rust: Add dma_fence abstractions
Date: Mon, 1 Jun 2026 13:44:57 +0000	[thread overview]
Message-ID: <ah2M2a_4PneZpjTS@google.com> (raw)
In-Reply-To: <24ef07ed85d9e7aa7f9d3a96301c4c15bc0f2315.camel@mailbox.org>

On Mon, Jun 01, 2026 at 03:14:05PM +0200, Philipp Stanner wrote:
> +Cc Boris
> 
> On Mon, 2026-06-01 at 14:55 +0200, Alice Ryhl wrote:
> > On Mon, Jun 1, 2026 at 2:34 PM Philipp Stanner <phasta@mailbox.org> wrote:
> > > 
> > > On Mon, 2026-06-01 at 10:20 +0000, Alice Ryhl wrote:
> > > > On Sat, May 30, 2026 at 03:06:21PM +0000, sashiko-bot@kernel.org wrote:
> > > > > > +impl<F: Send + Sync, C: Send + Sync> DriverFence<F, C> {
> > > > > > +    fn as_raw(&self) -> *mut bindings::dma_fence {
> > > > > > +        // SAFETY: Valid because `self` is valid.
> > > > > > +        let fence_data = unsafe { &mut *self.data.as_ptr() };
> > > > > 
> > > > > [Severity: High]
> > > > > Does this create an exclusive mutable reference to actively shared memory?
> > > > > 
> > > > > DriverFenceData can be accessed concurrently by other threads holding Fence
> > > > > references (for instance, when checking if the fence is signaled). Creating
> > > > > a mutable reference (&mut) in Rust asserts exclusive access and violates
> > > > > aliasing rules, which allows the compiler to make invalid optimization
> > > > > assumptions.
> > > > > 
> > > > > Could this use an immutable reference &*self.data.as_ptr() instead?
> > > > 
> > > > Yes, please use an immutable reference here.
> > > > 
> > > > > > +
> > > > > > +        fence_data.inner.inner.get()
> > > > > > +    }
> > > > > 
> > > > > [ ... ]
> > > > > 
> > > > > > +impl<F: Send + Sync, C: Send + Sync> DriverFenceBorrow<F, C> {
> > > > > > +    fn as_raw(&self) -> *mut bindings::dma_fence {
> > > > > > +        // SAFETY: Valid because `self` is valid.
> > > > > > +        let fence_data = unsafe { &mut *self.data.as_ptr() };
> > > > > 
> > > > > [Severity: High]
> > > > > Similar to DriverFence::as_raw(), does this also incorrectly create a
> > > > > mutable reference to shared data?
> > > > 
> > > > Here as well.
> > > 
> > > `data` is not shared. By design there is only ever one DriverFence, and
> > > the driver's data (`data.data`) is `Sync`.
> > > 
> > > But I guess an immutable one should do the trick, too.
> > 
> > There's only one DriverFence, but I can perform shared access to that
> > one DriverFence from two threads in parallel. You made the type Sync,
> > and this is what you are allowing when you do so.
> 
> Nope, DriverFence is just Send, not Sync.
> 
> data.data is Sync, but `data` in the code above is not the actual user
> data, but the memory backing it up.

Ok, well, it probably should be Sync. I don't see any &self methods that
can't be called from multiple threads in parallel.

> > > > > > +                bindings::dma_fence_signal_locked(fence);
> > > > > > +            }
> > > > > > +            bindings::dma_fence_unlock_irqrestore(fence, flag_ptr);
> > > > > > +        }
> > > > > > +
> > > > > > +        // SAFETY: `self.data` is owned by the DriverFence, but could be accessed
> > > > > > +        // through some dma_fence callbacks right now. Access is being revoked
> > > > > > +        // above by signalling the fence. The DriverFenceAllowedData trait
> > > > > > +        // ensures that the data either does not need drop, or if it does it
> > > > > > +        // lives in a RcuBox which will delay dropping by one grace period, hence
> > > > > > +        // ensuring that all readers have disappeared.
> > > > > > +        unsafe { drop_in_place(self.data.as_ptr()) };
> > > > > 
> > > > > [Severity: Critical]
> > > > > Could this eagerly drop FenceCtx and user data before the C dma_fence
> > > > > refcount reaches 0?
> > > > > 
> > > > > The C dma_fence object can remain alive as long as consumers (like sync_file
> > > > > or the GPU scheduler) hold references to it. If the backend later invokes
> > > > > callbacks like ops->get_driver_name(), FenceCtx::get_driver_name() would
> > > > > attempt to read fctx.driver_name from the already-dropped FenceCtx:
> > > > > 
> > > > > FenceCtx::get_driver_name() {
> > > > >     ...
> > > > >     fctx.driver_name.as_char_ptr()
> > > > > }
> > > > > 
> > > > > Can this result in a use-after-free?
> > > > 
> > > > Hmm, I don't know about what sahisko said, but I don't think this is the
> > > > right way to do rcu freeing. I think the type's destructor should be
> > > > reserved for cases where the value becomes immediately unusable.
> > > 
> > > We could guard the strings with RcuBox, but we could not then guard the
> > > FenceCtx code against code UAF if we don't have the rcu_barrier().
> > > 
> > > Or could we?
> > > 
> > > If a rust module unloads, module::remove() should contain an
> > > rcu_barrier() (right??). Would that be enough to guard against the
> > > FenceCtx code being unloaded?
> > > 
> > > > 
> > > > For example, let's say I'm using RcuBox<_> here. Yes, the data you get
> > > > from dereferencing the RcuBox will stay alive for a grace period, but
> > > > IMO once you run the destructor of the box itself, the *pointer* becomes
> > > > immediately unusable.
> > > 
> > > I don't know why you're stressing the pointer?
> > > 
> > > The trick above is simply that drop / dealloc *and* code unloading is
> > > delayed by a grace period.
> > 
> > Sorry let me try to rephrase. I'm not worried about the stuff behind
> > the pointer. After all, you're using RcuBox to protect that stuff.
> > What I'm worried about is the pointer itself. You invoked
> > drop_in_place() on the pointer to the fence context,
> > 
> 
> on the pointer to DriverFenceData, which contains a refcount to the
> FenceCtx, which might then want to drop.

Let me clarify.

You invoked drop_in_place on DriverFenceData which is effectively this
method:

fn drop_in_place::<DriverFenceData<F,C>>(self: *mut DriverFenceData) {
    drop_in_place::<Fence>(&raw mut (*self).fence);
    drop_in_place::<Arc<FenceCtx<F,C>>>(&raw mut (*self).fctx);
    drop_in_place::<F>(&raw mut (*self).data);
}

So yes you did indirectly invoke `drop_in_place` on Arc<FenceCtx<F,C>>.

> >  so even though
> > the fence context may be valid for another grace period, the *pointer*
> > to the fence context is not. The pointer could have been zeroed by the
> > destructor.
> 
> That particular pointer to the DriverFenceData could have been zeroed.
> But potential other accessors have already crafted themselves a new
> pointer to the, by the power of RCU, still valid data. That new pointer
> is container-of-ed from struct dma_fence *f.

I'm not talking about the pointer to DriverFenceData, I'm talking about
the pointer to the FenceCtx, or the pointer to the data (if F is
RcuBox).

The Arc type is not a type that opts-out of &mut == exclusive, so the
second drop_in_place() above is assumed exclusive access to the
Arc<FenceCtx<F,C>> field. If another thread obtains a pointer to the
FenceCtx via reading the fctx field of the DriverFence in parallel with
this, then that's not allowed because the drop_in_place() call has
exclusive access to that field.

This is why Boqun's RcuFreeSafe has a drop_in_place_before_gp() method
that can be used instead of drop_in_place() for this kind of use-case.
You must leave the fctx and data fields in a state where they contain
data that's safe to use for at least one grace period, and drop_in_place()
fundamentally does not leave the value in a usable state.

Alice

  parent reply	other threads:[~2026-06-01 13:45 UTC|newest]

Thread overview: 71+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-30 14:35 [PATCH 0/4] rust / dma_buf: Add abstractions for dma_fence Philipp Stanner
2026-05-30 14:35 ` [PATCH 1/4] rust: types: implement ForeignOwnable for ARef<T> Philipp Stanner
2026-05-30 14:45   ` sashiko-bot
2026-06-01  9:46   ` Alice Ryhl
2026-05-30 14:35 ` [PATCH 2/4] rust: rcu: add RcuBox type Philipp Stanner
2026-05-30 14:54   ` sashiko-bot
2026-05-30 15:08   ` Boqun Feng
2026-05-30 15:27     ` Danilo Krummrich
2026-06-01  7:56     ` Philipp Stanner
2026-06-01 13:41       ` Boqun Feng
2026-06-03  9:33         ` Philipp Stanner
2026-06-03  9:35           ` Alice Ryhl
2026-06-03 15:27           ` Boqun Feng
2026-06-03 17:36             ` Boqun Feng
2026-06-03 17:07   ` Boqun Feng
2026-05-30 14:35 ` [PATCH 3/4] rust: Add dma_fence abstractions Philipp Stanner
2026-05-30 15:06   ` sashiko-bot
2026-06-01 10:20     ` Alice Ryhl
2026-06-01 12:34       ` Philipp Stanner
2026-06-01 12:55         ` Alice Ryhl
2026-06-01 13:14           ` Philipp Stanner
2026-06-01 13:30             ` Philipp Stanner
2026-06-01 13:54               ` Alice Ryhl
2026-06-01 13:44             ` Alice Ryhl [this message]
2026-06-02 11:31               ` Philipp Stanner
2026-06-02 11:44                 ` Alice Ryhl
2026-06-02 11:52                   ` Philipp Stanner
2026-06-02 11:59                     ` Alice Ryhl
2026-06-02 12:06                       ` Philipp Stanner
2026-06-02 15:25                         ` Alice Ryhl
2026-06-03  6:10                           ` Philipp Stanner
2026-06-03  6:48                             ` Boris Brezillon
2026-06-03  7:43                               ` Philipp Stanner
2026-06-03  9:07                                 ` Philipp Stanner
2026-06-03  9:26                                   ` Alice Ryhl
2026-06-03  9:36                                     ` Philipp Stanner
2026-06-03  9:52                                 ` Boris Brezillon
2026-06-03  9:58                                   ` Boris Brezillon
2026-06-03 10:07                                     ` Philipp Stanner
2026-06-03 11:22                                       ` Boris Brezillon
2026-06-03 11:49                                         ` Philipp Stanner
2026-06-03 13:35                                           ` Boris Brezillon
2026-06-03 15:57                                         ` Danilo Krummrich
2026-06-03 16:34                                           ` Boris Brezillon
2026-06-03 19:43                                             ` Philipp Stanner
2026-06-03 16:51                                           ` Boris Brezillon
2026-05-30 15:16   ` Danilo Krummrich
2026-06-01  8:46     ` Philipp Stanner
2026-06-01 10:13       ` Danilo Krummrich
2026-06-01 10:36   ` Alice Ryhl
2026-06-01 10:59     ` Boris Brezillon
2026-06-01 11:17       ` Philipp Stanner
2026-06-01 12:35         ` Boris Brezillon
2026-06-01 12:26     ` Philipp Stanner
2026-06-01 12:39       ` Alice Ryhl
2026-06-01 12:47         ` Philipp Stanner
2026-06-01 13:22           ` Alice Ryhl
2026-06-01 13:23             ` Philipp Stanner
2026-06-01 13:27               ` Alice Ryhl
2026-06-01 12:37     ` Boris Brezillon
2026-06-03 16:41   ` Daniel Almeida
2026-06-03 17:14     ` Boris Brezillon
2026-06-04  0:43       ` Daniel Almeida
2026-06-04  8:15         ` Boris Brezillon
2026-06-05  7:56           ` Philipp Stanner
2026-06-05 16:00             ` Daniel Almeida
2026-06-05 16:02               ` Daniel Almeida
2026-06-05 15:51           ` Daniel Almeida
2026-05-30 14:35 ` [PATCH 4/4] MAINTAINERS: Add entry for Rust dma-buf Philipp Stanner
2026-05-30 15:20   ` Danilo Krummrich
2026-06-03 15:22 ` [PATCH 0/4] rust / dma_buf: Add abstractions for dma_fence Daniel Almeida

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=ah2M2a_4PneZpjTS@google.com \
    --to=aliceryhl@google.com \
    --cc=boris.brezillon@collabora.com \
    --cc=linux-media@vger.kernel.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 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.