* [PATCH] drm/vc4: drain the hangcheck timer and works on V3D unbind
@ 2026-09-09 5:35 Fan Wu
2026-09-09 5:51 ` sashiko-bot
0 siblings, 1 reply; 2+ messages in thread
From: Fan Wu @ 2026-09-09 5:35 UTC (permalink / raw)
To: mripard
Cc: dave.stevenson, mcanal, kernel-list, maarten.lankhorst,
tzimmermann, airlied, simona, eric, dri-devel, linux-kernel,
stable, Fan Wu
The hangcheck timer, which every submitted job arms and which queues
reset_work once a job stops making progress, and the job_done_work,
which the render-done interrupt queues to release completed jobs, are
never drained at teardown: vc4_irq_disable() cancels only
overflow_mem_work, and vc4_gem_destroy() runs from the drm-managed
release, after vc4_v3d_unbind() has already uninstalled the V3D
interrupt and cleared vc4->v3d.
A timer still armed by then reads V3D registers through the NULL
vc4->v3d pointer, and late callbacks run on the vc4_dev embedding
them after it has been freed.
Drain them in vc4_v3d_unbind(): shut the hangcheck timer down and
cancel reset_work before the interrupt is taken down, because
vc4_irq_reset() in a straggler reset re-enables it, then cancel
job_done_work once no source is left, before vc4->v3d is cleared.
This issue was found by an in-house static analysis tool.
Fixes: d5b1a78a772f ("drm/vc4: Add support for drawing 3D frames.")
Cc: stable@vger.kernel.org # 6.13+: vc4->gen does not exist on older trees
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/vc4/vc4_v3d.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c
index f32410420d3e..11d4df3164b4 100644
--- a/drivers/gpu/drm/vc4/vc4_v3d.c
+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
@@ -9,6 +9,7 @@
#include <linux/component.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/timer.h>
#include <drm/drm_print.h>
@@ -497,8 +498,18 @@ static void vc4_v3d_unbind(struct device *dev, struct device *master,
struct drm_device *drm = data;
struct vc4_dev *vc4 = to_vc4_dev(drm);
+ /* Kill the timer, then reset_work: vc4_irq_reset() re-enables it. */
+ if (vc4->gen == VC4_GEN_4) {
+ timer_shutdown_sync(&vc4->hangcheck.timer);
+ cancel_work_sync(&vc4->hangcheck.reset_work);
+ }
+
vc4_irq_uninstall(drm);
+ /* Nothing can queue job_done_work any more; drain it. */
+ if (vc4->gen == VC4_GEN_4)
+ cancel_work_sync(&vc4->job_done_work);
+
/* Disable the binner's overflow memory address, so the next
* driver probe (if any) doesn't try to reuse our old
* allocation.
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] drm/vc4: drain the hangcheck timer and works on V3D unbind
2026-09-09 5:35 [PATCH] drm/vc4: drain the hangcheck timer and works on V3D unbind Fan Wu
@ 2026-09-09 5:51 ` sashiko-bot
0 siblings, 0 replies; 2+ messages in thread
From: sashiko-bot @ 2026-09-09 5:51 UTC (permalink / raw)
To: Fan Wu; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [Medium] Canceling `job_done_work` without explicitly draining `job_done_list` directly leaks completed jobs and resources.
Pre-existing issues:
- [High] Missing drm_dev_enter() in DRM ioctls allows concurrent V3D unbind to directly cause a NULL pointer dereference.
- [High] Spurious interrupt execution directly after `vc4->v3d` clearance causes a NULL pointer crash.
--
commit c625fc5a6f0d8fd20c510d6e8829315b01c15ab3
Author: Fan Wu <fanwu01@zju.edu.cn>
drm/vc4: drain the hangcheck timer and works on V3D unbind
The hangcheck timer, which every submitted job arms and which queues
reset_work once a job stops making progress, and the job_done_work,
which the render-done interrupt queues to release completed jobs, are
never drained at teardown. This commit shuts the hangcheck timer down
and cancels reset_work and job_done_work during vc4_v3d_unbind().
> diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c
> index f32410420d3e4..11d4df3164b49 100644
> --- a/drivers/gpu/drm/vc4/vc4_v3d.c
> +++ b/drivers/gpu/drm/vc4/vc4_v3d.c
[ ... ]
> @@ -497,8 +498,18 @@ static void vc4_v3d_unbind(struct device *dev, struct device *master,
> struct drm_device *drm = data;
> struct vc4_dev *vc4 = to_vc4_dev(drm);
>
> + /* Kill the timer, then reset_work: vc4_irq_reset() re-enables it. */
> + if (vc4->gen == VC4_GEN_4) {
> + timer_shutdown_sync(&vc4->hangcheck.timer);
> + cancel_work_sync(&vc4->hangcheck.reset_work);
> + }
> +
> vc4_irq_uninstall(drm);
[Severity: High]
This is a pre-existing issue, but could this lead to a spurious interrupt
execution causing a NULL pointer crash?
When vc4_v3d_unbind() executes, it disables the hardware interrupts and later
sets vc4->v3d = NULL, but it does not unregister the IRQ handler (since it is
devm-managed by the parent device).
If a spurious interrupt arrives after this point, would vc4_irq() execute and
unconditionally dereference vc4->v3d via the V3D_READ macro, causing an
immediate crash?
>
> + /* Nothing can queue job_done_work any more; drain it. */
> + if (vc4->gen == VC4_GEN_4)
> + cancel_work_sync(&vc4->job_done_work);
[Severity: Medium]
Will this cancel_work_sync() directly leak completed jobs and resources?
If there are completed jobs pending in the job_done_list when the device is
unbound, the work is canceled before it can process the list.
Since no subsequent cleanup code (e.g., vc4_gem_destroy()) iterates over and
frees the items in job_done_list, won't these jobs and their associated BOs be
permanently leaked?
> +
> /* Disable the binner's overflow memory address, so the next
> * driver probe (if any) doesn't try to reuse our old
> * allocation.
[Severity: High]
This isn't a bug introduced by this patch, but does the ioctl path lack
drm_dev_enter() protection, allowing concurrent V3D unbind to directly cause
a NULL pointer dereference?
A user-space application could concurrently call DRM_IOCTL_VC4_SUBMIT_CL while
the administrator unbinds the v3d component via sysfs. The ioctl checks
if (!vc4->v3d) without holding a reference (e.g., drm_dev_enter()):
drivers/gpu/drm/vc4/vc4_gem.c:vc4_submit_cl_ioctl() {
if (!vc4->v3d) {
DRM_DEBUG("VC4_SUBMIT_CL with no VC4 V3D probed\n");
return -ENODEV;
}
...
}
Immediately after this check, vc4_v3d_unbind() executes and sets
vc4->v3d = NULL.
Would the ioctl then proceed to access vc4->v3d (e.g., in vc4_v3d_pm_get()),
resulting in a direct NULL pointer dereference?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260909053509.657074-1-fanwu01@zju.edu.cn?part=1
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-09-09 5:51 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-09 5:35 [PATCH] drm/vc4: drain the hangcheck timer and works on V3D unbind Fan Wu
2026-09-09 5:51 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox