[PATCH] drm/i915/gt: Fix rq use-after-free in signal_irq_work()

From: Wentao Liang

Date: Wed Sep 16 2026 - 14:52:02 EST


The final i915_request_put() can release the last reference to a
signaled request, freeing it synchronously (kmem_cache_free) before the
RCU iterator advances to read rq->signal_link.next. Grab the next
request up front, so the loop does not touch a request that may already
have been freed.

Fixes: c744d50363b7 ("drm/i915/gt: Split the breadcrumb spinlock between global and contexts")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Wentao Liang <vulab@xxxxxxxxxxx>
---
drivers/gpu/drm/i915/gt/intel_breadcrumbs.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c
index f840e98792cd..90bc32b526b8 100644
--- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c
+++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c
@@ -213,7 +213,7 @@ static void signal_irq_work(struct irq_work *work)
for (ce = list_first_or_null_rcu(&b->signalers, typeof(*ce), signal_link);
ce;
ce = cn) {
- struct i915_request *rq;
+ struct i915_request *rq, *rn;

/*
* Grab the next signaler up front, as dropping the final
@@ -223,9 +223,16 @@ static void signal_irq_work(struct irq_work *work)
cn = list_next_or_null_rcu(&b->signalers, &ce->signal_link,
typeof(*cn), signal_link);

- list_for_each_entry_rcu(rq, &ce->signals, signal_link) {
+ for (rq = list_first_or_null_rcu(&ce->signals,
+ typeof(*rq), signal_link);
+ rq;
+ rq = rn) {
bool release;

+ rn = list_next_or_null_rcu(&ce->signals,
+ &rq->signal_link,
+ typeof(*rn), signal_link);
+
if (!__i915_request_is_complete(rq))
break;

--
2.34.1