[PATCH] drm/bridge: ti-sn65dsi83: Cancel reset_work on remove to avoid use-after-free
Fan Wu <[email protected]> Wed, 5 Aug 2026 09:08:04 +0000
| Newsgroups | gmane.linux.kernel,gmane.comp.video.dri.devel,gmane.linux.kernel.stable |
|---|---|
| Message-ID | <[email protected]> |
The error recovery code queues ctx->reset_work from the threaded IRQ
handler and the polling monitor_work, but nothing ever cancels it.
sn65dsi83_remove() only unplugs the bridge, and the
sn65dsi83_release_resources devm action disables the IRQ at the chip and
stops monitor_work but does not cancel reset_work. The IRQ is
devm-managed, so a reset_work already queued survives detach and the devm
IRQ free and runs after ctx is freed, recovering it via container_of() and
leading to a use-after-free. drm_bridge_enter()/SRCU guards a running work
against bridge removal but cannot stop a queued work running after ctx is
gone.
Stop the producers before unplug, then drain: disable_irq so the threaded
handler can no longer queue reset_work, cancel monitor_work, then
cancel_work_sync(&ctx->reset_work). disable_irq keeps the IRQ registered
so a racing reset_work's trailing enable_irq() stays valid, while its
disable depth stops the handler from re-arming before ctx is freed.
This issue was found by an in-house static analysis tool.
Compile-tested only; runtime testing is appreciated.
Fixes: ad5c6ecef27e ("drm: bridge: ti-sn65dsi83: Add error recovery mechanism")
Cc: [email protected]
Assisted-by: Codex:gpt-5.6
Signed-off-by: Fan Wu <[email protected]>
---
drivers/gpu/drm/bridge/ti-sn65dsi83.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
index 42b451432bbb..d334b2898e25 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
@@ -1069,6 +1069,12 @@ static void sn65dsi83_remove(struct i2c_client *client)
{
struct sn65dsi83 *ctx = i2c_get_clientdata(client);
+ /* Stop the reset_work producers, then drain, before unplug. */
+ if (ctx->irq)
+ disable_irq(ctx->irq);
+ cancel_delayed_work_sync(&ctx->monitor_work);
+ cancel_work_sync(&ctx->reset_work);
+
drm_bridge_unplug(&ctx->bridge);
}
--
2.39.5