[PATCH] drm/sched: Free the run queues at the end of drm_sched_fini()

Donggeun Yoo posted 1 patch 2 weeks, 1 day ago
drivers/gpu/drm/scheduler/sched_main.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
[PATCH] drm/sched: Free the run queues at the end of drm_sched_fini()
Posted by Donggeun Yoo 2 weeks, 1 day ago
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@gmail.com/
Assisted-by: Claude:claude-fable-5
Signed-off-by: Donggeun Yoo <donggeunyoo.kernel@gmail.com>
---
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
Re: [PATCH] drm/sched: Free the run queues at the end of drm_sched_fini()
Posted by Tvrtko Ursulin 1 week, 4 days ago
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/20260910054605.634135-1-donggeunyoo.kernel@gmail.com/
> Assisted-by: Claude:claude-fable-5
> Signed-off-by: Donggeun Yoo <donggeunyoo.kernel@gmail.com>
> ---
> 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 <tvrtko.ursulin@igalia.com>

Regards,

Tvrtko
Re: [PATCH] drm/sched: Free the run queues at the end of drm_sched_fini()
Posted by Philipp Stanner 2 days, 8 hours ago
On Mon, 2026-09-14 at 13:11 +0100, Tvrtko Ursulin wrote:
> 
> 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/20260910054605.634135-1-donggeunyoo.kernel@gmail.com/
> > Assisted-by: Claude:claude-fable-5
> > Signed-off-by: Donggeun Yoo <donggeunyoo.kernel@gmail.com>
> > ---
> > Targets drm-misc-next (0878e6053d01).
> > 

[…]

> 
> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>

Applied it. Thx.

P.