* [PATCH] drm/lima: fix use-after-free of recover work on device removal
@ 2026-09-17 9:20 Fan Wu
2026-09-17 9:32 ` sashiko-bot
0 siblings, 1 reply; 2+ messages in thread
From: Fan Wu @ 2026-09-17 9:20 UTC (permalink / raw)
To: yuq825
Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
dri-devel, lima, linux-kernel, stable, Fan Wu
A recoverable GP error, reported by the GP or the GP MMU interrupt,
queues the pipe's recover_work on the system workqueue. Nothing drains
it on device removal: the worker can run after the GP task slab has
been destroyed, call drm_sched_fault() on a scheduler that
drm_sched_fini() has already torn down, or outlive the devm allocation
that embeds struct lima_device.
Free the GP and GP MMU interrupts, the only sources of recover_work,
before the GP pipe teardown, and drain the work while the task slab and
the scheduler are still alive. Stop the GP with a final reset after
drm_sched_fini(): nothing can restart the job anymore. Free the error
task list only after both schedulers are fini'd, as the timeout
handler locks it.
This issue was found by an in-house static analysis tool.
Fixes: 2081e8dcf1ee ("drm/lima: recover task by enlarging heap buffer")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5.6
Co-developed-by: Song Li <songl@zju.edu.cn>
Signed-off-by: Song Li <songl@zju.edu.cn>
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
---
drivers/gpu/drm/lima/lima_device.c | 22 +++++++++++++++++-----
drivers/gpu/drm/lima/lima_gp.c | 7 +++++++
drivers/gpu/drm/lima/lima_gp.h | 1 +
3 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c
index 0bf7105c8748..5f728230fce4 100644
--- a/drivers/gpu/drm/lima/lima_device.c
+++ b/drivers/gpu/drm/lima/lima_device.c
@@ -297,8 +297,14 @@ static void lima_fini_gp_pipe(struct lima_device *dev)
{
struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp;
- lima_gp_pipe_fini(dev);
+ cancel_work_sync(&pipe->recover_work);
+
lima_sched_pipe_fini(pipe);
+
+ /* a recovery may have restarted the GP job */
+ lima_gp_stop(dev->ip + lima_ip_gp);
+
+ lima_gp_pipe_fini(dev);
}
static int lima_init_pp_pipe(struct lima_device *dev)
@@ -442,17 +448,23 @@ void lima_device_fini(struct lima_device *ldev)
int i;
struct lima_sched_error_task *et, *tmp;
+ lima_fini_pp_pipe(ldev);
+
+ /* free the IRQ sources of recover_work before the GP pipe drain */
+ lima_fini_ip(ldev, lima_ip_gp);
+ lima_fini_ip(ldev, lima_ip_gpmmu);
+ lima_fini_gp_pipe(ldev);
+
+ /* the timeout handlers lock it: free after both schedulers */
list_for_each_entry_safe(et, tmp, &ldev->error_task_list, list) {
list_del(&et->list);
kvfree(et);
}
mutex_destroy(&ldev->error_task_list_lock);
- lima_fini_pp_pipe(ldev);
- lima_fini_gp_pipe(ldev);
-
for (i = lima_ip_num - 1; i >= 0; i--)
- lima_fini_ip(ldev, i);
+ if (i != lima_ip_gp && i != lima_ip_gpmmu)
+ lima_fini_ip(ldev, i);
if (ldev->dlbu_cpu)
dma_free_wc(ldev->dev, LIMA_PAGE_SIZE,
diff --git a/drivers/gpu/drm/lima/lima_gp.c b/drivers/gpu/drm/lima/lima_gp.c
index 3282997a0358..7287af7829f8 100644
--- a/drivers/gpu/drm/lima/lima_gp.c
+++ b/drivers/gpu/drm/lima/lima_gp.c
@@ -350,6 +350,13 @@ void lima_gp_fini(struct lima_ip *ip)
devm_free_irq(dev->dev, ip->irq, ip);
}
+/* keep the irq masked: hard_reset() re-enables it */
+void lima_gp_stop(struct lima_ip *ip)
+{
+ lima_gp_hard_reset(ip);
+ gp_write(LIMA_GP_INT_MASK, 0);
+}
+
int lima_gp_pipe_init(struct lima_device *dev)
{
int frame_size = sizeof(struct drm_lima_gp_frame);
diff --git a/drivers/gpu/drm/lima/lima_gp.h b/drivers/gpu/drm/lima/lima_gp.h
index 02ec9af78a51..c2a1e54ea567 100644
--- a/drivers/gpu/drm/lima/lima_gp.h
+++ b/drivers/gpu/drm/lima/lima_gp.h
@@ -11,6 +11,7 @@ int lima_gp_resume(struct lima_ip *ip);
void lima_gp_suspend(struct lima_ip *ip);
int lima_gp_init(struct lima_ip *ip);
void lima_gp_fini(struct lima_ip *ip);
+void lima_gp_stop(struct lima_ip *ip);
int lima_gp_pipe_init(struct lima_device *dev);
void lima_gp_pipe_fini(struct lima_device *dev);
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] drm/lima: fix use-after-free of recover work on device removal
2026-09-17 9:20 [PATCH] drm/lima: fix use-after-free of recover work on device removal Fan Wu
@ 2026-09-17 9:32 ` sashiko-bot
0 siblings, 0 replies; 2+ messages in thread
From: sashiko-bot @ 2026-09-17 9:32 UTC (permalink / raw)
To: Fan Wu; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] drm/lima: unhandled interrupt storm during device teardown
--
commit 8abd934c293282a7fc2e36fd5ffb16c36332e554
Author: Fan Wu <fanwu01@zju.edu.cn>
drm/lima: fix use-after-free of recover work on device removal
This commit fixes a use-after-free issue on device removal by draining the
recover_work while the task slab and scheduler are still alive. It frees the
GP and GP MMU interrupts before the GP pipe teardown and stops the GP after
the scheduler is finished.
> diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c
> index 7c873e62c16da..e4dbd8baf33c6 100644
> --- a/drivers/gpu/drm/lima/lima_device.c
> +++ b/drivers/gpu/drm/lima/lima_device.c
> @@ -297,8 +297,14 @@ static void lima_fini_gp_pipe(struct lima_device *dev)
> {
> struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp;
>
> - lima_gp_pipe_fini(dev);
> + cancel_work_sync(&pipe->recover_work);
> +
> lima_sched_pipe_fini(pipe);
> +
> + /* a recovery may have restarted the GP job */
> + lima_gp_stop(dev->ip + lima_ip_gp);
> +
> + lima_gp_pipe_fini(dev);
> }
>
[ ... ]
> @@ -442,17 +448,23 @@ void lima_device_fini(struct lima_device *ldev)
> int i;
> struct lima_sched_error_task *et, *tmp;
>
> + lima_fini_pp_pipe(ldev);
> +
> + /* free the IRQ sources of recover_work before the GP pipe drain */
> + lima_fini_ip(ldev, lima_ip_gp);
> + lima_fini_ip(ldev, lima_ip_gpmmu);
> + lima_fini_gp_pipe(ldev);
[Severity: High]
Could unregistering the IRQ handlers before draining the GP pipe lead to an
unhandled interrupt storm?
The call to lima_fini_gp_pipe() executes cancel_work_sync(&pipe->recover_work).
If recover_work is executing concurrently during device teardown,
cancel_work_sync() will wait for it to complete.
The recovery work calls lima_gp_task_recover(), which explicitly unmasks the
GP hardware interrupts and resumes hardware execution:
gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED);
When the hardware subsequently completes the job or faults, it will assert the
IRQ line. Because the IRQ handler was already freed by the calls to
lima_fini_ip() above, the interrupt goes unhandled.
Could this cause the generic IRQ subsystem to permanently disable the shared
IRQ line and break other devices sharing it?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260917092027.192956-1-fanwu01@zju.edu.cn?part=1
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-09-17 9:32 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-17 9:20 [PATCH] drm/lima: fix use-after-free of recover work on device removal Fan Wu
2026-09-17 9:32 ` sashiko-bot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.