All of lore.kernel.org
 help / color / mirror / Atom feed
From: Philipp Stanner <phasta@kernel.org>
To: "Sumit Semwal" <sumit.semwal@linaro.org>,
	"Christian König" <christian.koenig@amd.com>,
	"Jani Nikula" <jani.nikula@linux.intel.com>,
	"Joonas Lahtinen" <joonas.lahtinen@linux.intel.com>,
	"Rodrigo Vivi" <rodrigo.vivi@intel.com>,
	"Tvrtko Ursulin" <tursulin@ursulin.net>,
	"David Airlie" <airlied@gmail.com>,
	"Simona Vetter" <simona@ffwll.ch>,
	"Steven Rostedt" <rostedt@goodmis.org>,
	"Masami Hiramatsu" <mhiramat@kernel.org>,
	"Mathieu Desnoyers" <mathieu.desnoyers@efficios.com>,
	"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>,
	"Daniel Almeida" <daniel.almeida@collabora.com>,
	"Tamir Duberstein" <tamird@kernel.org>,
	"Alexandre Courbot" <acourbot@nvidia.com>,
	"Onur Özkan" <work@onurozkan.dev>,
	"Boris Brezillon" <boris.brezillon@collabora.com>,
	"Alex Deucher" <alexdeucher@gmail.com>
Cc: linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org,
	linux-kernel@vger.kernel.org, intel-gfx@lists.freedesktop.org,
	linux-trace-kernel@vger.kernel.org,
	rust-for-linux@vger.kernel.org,
	Philipp Stanner <phasta@kernel.org>
Subject: [RFC PATCH v2 2/3] dma-fence: use lock to protect against module-unload
Date: Tue, 20 Oct 2026 12:00:33 +0200	[thread overview]
Message-ID: <20261020100034.759183-4-phasta@kernel.org> (raw)
In-Reply-To: <20261020100034.759183-2-phasta@kernel.org>

dma_fence's lock already guards the signaled-state, and most fence
backend_ops callbacks are already called with the lock taken.

The contract already relies on the fact that a producer must signal all
fences before unloading. The callbacks then must never run on a fence
that is already signaled.

Currently, driver unload is supported by RCU-checking the fence->ops
pointer. However, the design ended up with two partially redundant
mechanisms, the other being the signaled-state:

	/*
	 * Make load ordering irrelevant by checking both signaled state and ops
	 * pointer and ops pointer is only set to NULL on newer implementations.
	 */
	if (!dma_fence_test_signaled_flag(fence) && ops)

We have seen multiple bugs, such as ordering issues, because of that,
for instance in:

035219a760ed ("dma-buf: dma-fence: Fix potential NULL pointer dereference")
3ed11c671ff7 ("dma-buf/dma-fence: fix checking signaling bit for timeline and driver name v3")

Additionally, our RCU requirements can by definition not be controled by
dma_fence, resulting in a burden on users and an unnecessary grace
period delay. Most recently, this came to light in CRTC:

https://lore.kernel.org/dri-devel/d54ba24b0a4748b5c00052d4542460ea014aa50d.camel@mailbox.org/

It appears to be the natural solution to guard the fence's signaled
state *and* accesses to the driver and its data through the lock.
However, in the past it has been argued that one cannot hold the
fence-lock while running a callback, because this might lead to
deadlocks, since drivers might want to access data protected by a driver
lock.

De-facto, it is already the case that ops callbacks are called with the
lock taken, and don't run into the driver if the fence is signaled
already. Thus, we merely need to make that rule official.

This commit proposes making it standard to guard against UAF and module
unload by holding the lock while running fence->ops.

The current situation of the ops is like this:

- release() and wait() are deprecated and can never work with module
  unload in any case, thus neither RCU nor lock help them anyways.

- enable_signaling() and is_signaled() are already being invoked with the
  lock, thus continue doing so is fine.

- get_driver_name() and get_timeline_name() can elegantly be solved by
  copying the name-strings. See subsequent patch.

- set_deadline() is the only callback for which a locked call would be
  new. It has very few implementors, so correctness is easy to verify.

For dma_fence_is_signaled(), dma_fence_is_signaled_locked()'s existence
proofs that we can lock the former's ops->signaled() call, too.

The fact that most callbacks are already invoked with the lock taken
proofs that the drivers support it, and doing it consistently will make
the entire API far more robust and consistent than RCU-guarding.

Current users keep working, and future users can be well-informed about
the locking considerations.

Let's go for full, consistent locking. Add lock guards around the two
missing paths running into non-deprecated backend_ops.

Signed-off-by: Philipp Stanner <phasta@kernel.org>
---
 drivers/dma-buf/dma-fence.c |  7 ++++++-
 include/linux/dma-fence.h   | 21 +++++++++++++++++----
 2 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index 5dab647e3f3f..e4350bce9cf9 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -997,9 +997,14 @@ 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 = fence->ops;
+	unsigned long flags;
 
-	if (ops->set_deadline && !dma_fence_is_signaled(fence))
+	dma_fence_lock_irqsave(fence, flags);
+
+	if (ops->set_deadline && !dma_fence_is_signaled_locked(fence))
 		ops->set_deadline(fence, deadline);
+
+	dma_fence_unlock_irqrestore(fence, flags);
 }
 EXPORT_SYMBOL(dma_fence_set_deadline);
 
diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
index 874848a4aec4..2223d75c5a49 100644
--- a/include/linux/dma-fence.h
+++ b/include/linux/dma-fence.h
@@ -549,16 +549,29 @@ static inline bool
 dma_fence_is_signaled(struct dma_fence *fence)
 {
 	const struct dma_fence_ops *ops = fence->ops;
+	unsigned long flags;
+	bool ret = false;
 
+	/* Fast-path optimization. */
 	if (dma_fence_test_signaled_flag(fence))
 		return true;
 
-	if (ops && ops->signaled && ops->signaled(fence)) {
-		dma_fence_signal(fence);
-		return true;
+	dma_fence_lock_irqsave(fence, flags);
+
+	if (dma_fence_test_signaled_flag(fence)) {
+		ret = true;
+		goto out;
 	}
 
-	return false;
+	if (ops->signaled && ops->signaled(fence)) {
+		ret = true;
+		dma_fence_signal_locked(fence);
+	}
+
+out:
+	dma_fence_unlock_irqrestore(fence, flags);
+
+	return ret;
 }
 
 /**
-- 
2.56.0


  parent reply	other threads:[~2026-10-20 10:01 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-20 10:00 [RFC PATCH v2 0/3] Solve dma_fence's problems by locking Philipp Stanner
2026-10-20 10:00 ` [RFC PATCH v2 1/3] dma-fence: Remove RCU protection for fence->ops Philipp Stanner
2026-10-20 10:20   ` sashiko-bot
2026-10-20 10:00 ` Philipp Stanner [this message]
2026-10-20 10:19   ` [RFC PATCH v2 2/3] dma-fence: use lock to protect against module-unload sashiko-bot
2026-10-20 10:00 ` [RFC PATCH v2 3/3] dma-fence: Support unload for ops->get_XXX_name() Philipp Stanner
2026-10-20 10:27   ` sashiko-bot
2026-10-20 11:48 ` ✓ i915.CI.BAT: success for Solve dma_fence's problems by locking Patchwork
2026-10-20 12:02 ` [RFC PATCH v2 0/3] " Christian König
2026-10-20 14:41   ` Philipp Stanner
2026-10-20 15:07     ` Christian König

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=20261020100034.759183-4-phasta@kernel.org \
    --to=phasta@kernel.org \
    --cc=a.hindborg@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=airlied@gmail.com \
    --cc=alexdeucher@gmail.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=gary@garyguo.net \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=jani.nikula@linux.intel.com \
    --cc=joonas.lahtinen@linux.intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=linux-trace-kernel@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=mhiramat@kernel.org \
    --cc=ojeda@kernel.org \
    --cc=rodrigo.vivi@intel.com \
    --cc=rostedt@goodmis.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=simona@ffwll.ch \
    --cc=sumit.semwal@linaro.org \
    --cc=tamird@kernel.org \
    --cc=tmgross@umich.edu \
    --cc=tursulin@ursulin.net \
    --cc=work@onurozkan.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.