On 10/09/2026 13:16, Donggeun Yoo wrote:
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/[email protected]/
Assisted-by: Claude:claude-fable-5
Signed-off-by: Donggeun Yoo <[email protected]>
---
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;

Reviewed-by: Tvrtko Ursulin <[email protected]>

Regards,

Tvrtko

Reply via email to