[PATCH] drm/sched: Free the run queues at the end of drm_sched_fini()
From: Donggeun Yoo
Date: Thu Sep 10 2026 - 08:25:16 EST
drm_sched_fini() frees the run queues at the top of teardown but the array
holding them at the bottom. The early half is on the wrong side of
cancel_delayed_work_sync(&sched->work_tdr), which waits for a timeout
handler that can still walk sched->sched_rq[i] through
drm_sched_increase_karma().
No correct driver can be there, since every fence returned from run_job()
must be signaled before drm_sched_fini() is called. Free the entries next
to the array anyway, so run-queue teardown happens in one place.
Link: https://lore.kernel.org/dri-devel/20260910054605.634135-1-donggeunyoo.kernel@xxxxxxxxx/
Assisted-by: Claude:claude-fable-5
Signed-off-by: Donggeun Yoo <donggeunyoo.kernel@xxxxxxxxx>
---
Targets drm-misc-next (0878e6053d01).
A cleanup - no Fixes:, no Cc: stable.
The KUnit case and how to run it:
https://github.com/donggeunyoo/drm-sched-fini-uaf-repro
x86_64 under QEMU, KUNIT + KASAN + lockdep, whole drm_sched suite, three
runs per arm:
before 38-41 KASAN slab-use-after-free reports, all from
drm_sched_increase_karma() on the timeout worker
after 0
drivers/gpu/drm/scheduler/sched_main.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c
index 6cb6f9546493..fec04c944c5e 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -1210,9 +1210,6 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched)
drm_sched_wqueue_stop(sched);
- for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++)
- kfree(sched->sched_rq[i]);
-
/* Wakeup everyone stuck in drm_sched_entity_flush for this scheduler */
wake_up_all(&sched->job_scheduled);
@@ -1226,6 +1223,9 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched)
if (sched->own_submit_wq)
destroy_workqueue(sched->submit_wq);
sched->ready = false;
+
+ for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++)
+ kfree(sched->sched_rq[i]);
kfree(sched->sched_rq);
sched->sched_rq = NULL;
--
2.53.0