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

Wentao Liang posted 1 patch 1 week, 1 day ago
drivers/gpu/drm/i915/gt/intel_breadcrumbs.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
[PATCH] drm/i915/gt: Fix rq use-after-free in signal_irq_work()
Posted by Wentao Liang 1 week, 1 day ago
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@vger.kernel.org
Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
---
 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