The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: Philipp Stanner <phasta@mailbox.org>
To: "Christian König" <christian.koenig@amd.com>,
	"Philipp Stanner" <phasta@kernel.org>,
	"Sumit Semwal" <sumit.semwal@linaro.org>,
	"Boris Brezillon" <boris.brezillon@collabora.com>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Daniel Almeida" <dwlsalmeida@gmail.com>,
	"Gary Guo" <gary@garyguo.net>,
	"Tvrtko Ursulin" <tvrtko.ursulin@igalia.com>
Cc: linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org,
	 linux-kernel@vger.kernel.org, Danilo Krummrich <dakr@kernel.org>
Subject: Re: [RFC PATCH] dma-fence: Fix races of fence callbacks versus destructors by locking
Date: Mon, 08 Jun 2026 17:41:31 +0200	[thread overview]
Message-ID: <fa9a335196525adbc03ec21b2e05bb526e4fc174.camel@mailbox.org> (raw)
In-Reply-To: <95f4ae6b-9dec-4122-84e0-fbb0cdee9cb5@amd.com>

On Mon, 2026-06-08 at 17:35 +0200, Christian König wrote:
> On 6/8/26 16:24, Philipp Stanner wrote:
> > The dma_fence backend_ops can access a fence. Hereby, a driver callback
> > will be running which likely will access driver specific data through
> > container_of(). If now, simultaneously, a driver signals the fence and
> > afterwards expects to run a driver specific destructor (using the same
> > data accessed through container_of()), there can be a race.
> > 
> > A driver very likely trusts that once it has signaled a fence, no one
> > will be accessing it anymore. Moreover, it might already want to free up
> > resources, making UAF bugs possible.
> > 
> > The race occurs because there are only pragmatic checks for the signaled
> > flag of a fence, without taking the fence lock. RCU guards exist, but
> > their purpose is to guard accesses through the backend_ops callbacks
> > against the driver (which implements the TEXT segment these callbacks
> > live in) from unloading.
> > 
> > Proper synchronization can be ensured by taking the fence lock. RCU is
> > still simultaneously required to guard against the unload.
> > 
> > Fix the races by taking the lock for all non-deprecated backend_ops
> > callbacks.
> 
> That sounds like the fundamentally wrong approach to me.
> 
> The lock protects the dma_fence signaling state and *NOT* any driver
> state, so it should not be used to protect any driver state.
> 
> Drivers need to make sure that they protect their driver state with
> separate lock and don't rely on the dma_fence lock for this. This is
> actually the core of why we want to deprecate the shared dma_fence
> spinlock.

It's not so much about protecting data, it's about correctness:

A driver that calls

dma_fence_signal(f)

expects that after signalling, no callback will be running into the
driver again. It's a fix synchronization point.

Only the fence lock can grant such synchronization.

Positive effects would be:

1. Drivers can do their cleanup immediately, without having to wait for
a grace period

2. Drivers could be sure that their driver_fence data, allocated
together with fence and accessed through container_of(fence), is not
being accessed anymore.


I see only advantages. Safer, faster. :)

P.

> 
> Regards,
> Christian.
> 
> > 
> > Conveniently, this also fixes a race where backend_ops->set_deadline()
> > might try to set a deadline for an already signaled fence.
> > 
> > Suggested-by: Danilo Krummrich <dakr@kernel.org>
> > Signed-off-by: Philipp Stanner <phasta@kernel.org>
> > ---
> > We discovered this problem through our Rust abstractions, but it can
> > also occur in C.
> > 
> > The by far cleanest solution seems to be to use the fence lock. This RFC
> > serves to discuss whether there is anything preventing that.
> > 
> > (Patch so far just compile tested, to have some groundlayer for the
> > rough idea, to discuss it first)
> > ---
> >  drivers/dma-buf/dma-fence.c | 39 ++++++++++++++++++++++++++++---------
> >  include/linux/dma-fence.h   | 17 ++++++++++++----
> >  2 files changed, 43 insertions(+), 13 deletions(-)
> > 
> > diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
> > index c7ea1e75d38a..b74f02f3cca8 100644
> > --- a/drivers/dma-buf/dma-fence.c
> > +++ b/drivers/dma-buf/dma-fence.c
> > @@ -629,7 +629,8 @@ EXPORT_SYMBOL(dma_fence_free);
> >  static bool __dma_fence_enable_signaling(struct dma_fence *fence)
> >  {
> >  	const struct dma_fence_ops *ops;
> > -	bool was_set;
> > +	bool was_set, success;
> > +	unsigned long flags;
> >  
> >  	dma_fence_assert_held(fence);
> >  
> > @@ -644,7 +645,10 @@ static bool __dma_fence_enable_signaling(struct dma_fence *fence)
> >  	if (!was_set && ops && ops->enable_signaling) {
> >  		trace_dma_fence_enable_signal(fence);
> >  
> > -		if (!ops->enable_signaling(fence)) {
> > +		dma_fence_lock_irqsave(fence, flags);
> > +		success = ops->enable_signaling(fence);
> > +		dma_fence_unlock_irqrestore(fence, flags);
> > +		if (!success) {
> >  			rcu_read_unlock();
> >  			dma_fence_signal_locked(fence);
> >  			return false;
> > @@ -1020,11 +1024,20 @@ EXPORT_SYMBOL(dma_fence_wait_any_timeout);
> >  void dma_fence_set_deadline(struct dma_fence *fence, ktime_t deadline)
> >  {
> >  	const struct dma_fence_ops *ops;
> > +	unsigned long flags;
> >  
> >  	rcu_read_lock();
> >  	ops = rcu_dereference(fence->ops);
> > -	if (ops && ops->set_deadline && !dma_fence_is_signaled(fence))
> > +	if (!ops || !ops->set_deadline) {
> > +		rcu_read_unlock();
> > +		return;
> > +	}
> > +
> > +	dma_fence_lock_irqsave(fence, flags);
> > +	if (!dma_fence_is_signaled_locked(fence))
> >  		ops->set_deadline(fence, deadline);
> > +
> > +	dma_fence_unlock_irqrestore(fence, flags);
> >  	rcu_read_unlock();
> >  }
> >  EXPORT_SYMBOL(dma_fence_set_deadline);
> > @@ -1166,14 +1179,18 @@ EXPORT_SYMBOL(dma_fence_init64);
> >   */
> >  const char __rcu *dma_fence_driver_name(struct dma_fence *fence)
> >  {
> > +	const char __rcu *name = "detached-driver";
> >  	const struct dma_fence_ops *ops;
> > +	unsigned long flags;
> >  
> >  	/* RCU protection is required for safe access to returned string */
> >  	ops = rcu_dereference(fence->ops);
> > +	dma_fence_lock_irqsave(fence, flags);
> >  	if (!dma_fence_test_signaled_flag(fence))
> > -		return (const char __rcu *)ops->get_driver_name(fence);
> > -	else
> > -		return (const char __rcu *)"detached-driver";
> > +		name = ops->get_driver_name(fence);
> > +	dma_fence_unlock_irqrestore(fence, flags);
> > +
> > +	return name;
> >  }
> >  EXPORT_SYMBOL(dma_fence_driver_name);
> >  
> > @@ -1199,13 +1216,17 @@ EXPORT_SYMBOL(dma_fence_driver_name);
> >   */
> >  const char __rcu *dma_fence_timeline_name(struct dma_fence *fence)
> >  {
> > +	const char __rcu *name = "signaled-timeline";
> >  	const struct dma_fence_ops *ops;
> > +	unsigned long flags;
> >  
> >  	/* RCU protection is required for safe access to returned string */
> >  	ops = rcu_dereference(fence->ops);
> > +	dma_fence_lock_irqsave(fence, flags);
> >  	if (!dma_fence_test_signaled_flag(fence))
> > -		return (const char __rcu *)ops->get_driver_name(fence);
> > -	else
> > -		return (const char __rcu *)"signaled-timeline";
> > +		name = ops->get_driver_name(fence);
> > +	dma_fence_unlock_irqrestore(fence, flags);
> > +
> > +	return name;
> >  }
> >  EXPORT_SYMBOL(dma_fence_timeline_name);
> > diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
> > index b52ab692b22e..b93c3f7f69fb 100644
> > --- a/include/linux/dma-fence.h
> > +++ b/include/linux/dma-fence.h
> > @@ -547,20 +547,29 @@ static inline bool
> >  dma_fence_is_signaled(struct dma_fence *fence)
> >  {
> >  	const struct dma_fence_ops *ops;
> > +	unsigned long flags;
> > +	bool signaled;
> >  
> >  	if (dma_fence_test_signaled_flag(fence))
> >  		return true;
> >  
> >  	rcu_read_lock();
> >  	ops = rcu_dereference(fence->ops);
> > -	if (ops && ops->signaled && ops->signaled(fence)) {
> > +	if (!ops || !ops->signaled) {
> >  		rcu_read_unlock();
> > -		dma_fence_signal(fence);
> > -		return true;
> > +		return false;
> >  	}
> > +
> > +	dma_fence_lock_irqsave(fence, flags);
> > +	signaled = ops->signaled(fence);
> > +
> > +	if (signaled)
> > +		dma_fence_signal_locked(fence);
> > +
> > +	dma_fence_unlock_irqrestore(fence, flags);
> >  	rcu_read_unlock();
> >  
> > -	return false;
> > +	return signaled;
> >  }
> >  
> >  /**

  reply	other threads:[~2026-06-08 15:41 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-08 14:24 [RFC PATCH] dma-fence: Fix races of fence callbacks versus destructors by locking Philipp Stanner
2026-06-08 15:01 ` Boris Brezillon
2026-06-08 15:17   ` Philipp Stanner
2026-06-08 15:23     ` Danilo Krummrich
2026-06-08 15:30       ` Boris Brezillon
2026-06-08 15:30       ` Philipp Stanner
2026-06-08 16:16         ` Boris Brezillon
2026-06-09  8:02           ` Christian König
2026-06-09  8:54             ` Philipp Stanner
2026-06-09  8:43           ` Philipp Stanner
2026-06-09  8:47             ` Christian König
2026-06-09  9:00               ` Philipp Stanner
2026-06-08 15:07 ` Tvrtko Ursulin
2026-06-08 15:15   ` Philipp Stanner
2026-06-08 15:35 ` Christian König
2026-06-08 15:41   ` Philipp Stanner [this message]
2026-06-08 17:34     ` Christian König
2026-06-08 17:59       ` Danilo Krummrich
2026-06-08 18:32         ` Christian König
2026-06-08 18:39           ` Danilo Krummrich
2026-06-08 18:47             ` Christian König
2026-06-08 19:25               ` Danilo Krummrich
2026-06-09  8:17                 ` Christian König
2026-06-09  5:52               ` Philipp Stanner
2026-06-09 10:26                 ` Christian König
2026-06-09 10:42                   ` Philipp Stanner
2026-06-09 10:53                     ` Christian König
2026-06-09 11:39                       ` Philipp Stanner
2026-06-09 13:19               ` Philipp Stanner
2026-06-09 13:34                 ` Christian König
2026-06-10 14:25                   ` Philipp Stanner
2026-06-10 15:15                     ` Christian König
2026-06-11  8:35                       ` Philipp Stanner
2026-06-11  9:14                         ` Christian König
2026-06-11  9:50                           ` Philipp Stanner
2026-06-11 11:06                             ` Christian König
2026-06-09 13:36                 ` Tvrtko Ursulin
2026-06-09 13:57                   ` Philipp Stanner
2026-06-09 14:03                     ` Christian König
2026-06-15  8:29           ` Properly synchronize dma_fence->signaled bit (Was: Re: [RFC PATCH] dma-fence: Fix races of fence callbacks versus destructors by locking) Philipp Stanner
2026-06-15  9:57             ` Christian König
2026-06-16 11:25               ` Philipp Stanner
2026-06-17  9:46                 ` Christian König
2026-06-17 10:16                   ` Philipp Stanner
2026-06-17 13:03                     ` Christian König
2026-06-17 13:21                       ` Philipp Stanner
2026-06-17 13:50                   ` Gary Guo

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=fa9a335196525adbc03ec21b2e05bb526e4fc174.camel@mailbox.org \
    --to=phasta@mailbox.org \
    --cc=aliceryhl@google.com \
    --cc=boris.brezillon@collabora.com \
    --cc=christian.koenig@amd.com \
    --cc=dakr@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=dwlsalmeida@gmail.com \
    --cc=gary@garyguo.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=phasta@kernel.org \
    --cc=sumit.semwal@linaro.org \
    --cc=tvrtko.ursulin@igalia.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