[PATCH v7 04/19] media: meson: vdec: Fix use-after-free race between teardown and ISR routines
From: Anand Moon
Date: Mon Jul 13 2026 - 08:09:43 EST
Prevent critical race conditions and null pointer dereferences inside
the Amlogic video decoder driver by synchronizing the interrupt service
routines during session teardown and file descriptor release phases.
The hardware interrupt handler (vdec_isr) and threaded handler
(vdec_threaded_isr) read 'core->cur_sess' without proper synchronization.
During a streaming teardown sequence via vdec_stop_streaming() or session
release inside vdec_close(), the underlying session structures can be
modified or freed concurrently. This creates a transient window where a
late-stage hardware interrupt can wake up, read 'core->cur_sess', and
dereference an invalid or NULL session pointer, causing a kernel panic.
Update both the hard and threaded interrupt service routines to capture
the current session reference using an smp_load_acquire() barrier snapshot.
If the snapshot resolves to NULL, terminate immediately with IRQ_HANDLED
to guarantee execution contexts do not process stale structures.
Cc: Nicolas Dufresne <nicolas@xxxxxxxxxxxx>
Suggested-by: Druk Tan Ozturk <doruk@xxxxxxx>
Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
Closes: https://lore.kernel.org/all/20260521090944.F35401F00A3D@xxxxxxxxxxxxxxx/
Signed-off-by: Anand Moon <linux.amoon@xxxxxxxxx>
---
drivers/staging/media/meson/vdec/vdec.c | 22 ++++++++++++++++++++--
drivers/staging/media/meson/vdec/vdec.h | 2 ++
2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c
index 7fc73d5cdebbf..7ae3d5a9dd6ab 100644
--- a/drivers/staging/media/meson/vdec/vdec.c
+++ b/drivers/staging/media/meson/vdec/vdec.c
@@ -484,6 +484,9 @@ static void vdec_stop_streaming(struct vb2_queue *q)
}
}
+ /* Synchronize and flush pending hardware interrupt service routines */
+ synchronize_irq(core->vdec_irq);
+
vdec_poweroff(sess);
vdec_free_canvas(sess);
@@ -989,6 +992,9 @@ static int vdec_close(struct file *file)
struct amvdec_session *sess = file_to_amvdec_session(file);
struct amvdec_core *core = sess->core;
+ /* Synchronize and flush pending hardware interrupt service routines */
+ synchronize_irq(core->vdec_irq);
+
if (!IS_ERR_OR_NULL(sess->recycle_thread)) {
kthread_stop(sess->recycle_thread);
sess->recycle_thread = NULL;
@@ -1038,7 +1044,12 @@ static const struct v4l2_file_operations vdec_fops = {
static irqreturn_t vdec_isr(int irq, void *data)
{
struct amvdec_core *core = data;
- struct amvdec_session *sess = core->cur_sess;
+ struct amvdec_session *sess;
+
+ /* Secure an atomic acquire snapshot to protect against concurrent teardown */
+ sess = smp_load_acquire(&core->cur_sess);
+ if (!sess)
+ return IRQ_HANDLED;
sess->last_irq_jiffies = get_jiffies_64();
@@ -1048,7 +1059,12 @@ static irqreturn_t vdec_isr(int irq, void *data)
static irqreturn_t vdec_threaded_isr(int irq, void *data)
{
struct amvdec_core *core = data;
- struct amvdec_session *sess = core->cur_sess;
+ struct amvdec_session *sess;
+
+ /* Prevent late-stage threaded interrupts from dereferencing a NULL session */
+ sess = smp_load_acquire(&core->cur_sess);
+ if (!sess)
+ return IRQ_HANDLED;
return sess->fmt_out->codec_ops->threaded_isr(sess);
}
@@ -1136,6 +1152,8 @@ static int vdec_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
+ core->vdec_irq = irq;
+
ret = devm_request_threaded_irq(core->dev, irq, vdec_isr,
vdec_threaded_isr, IRQF_ONESHOT,
"vdec", core);
diff --git a/drivers/staging/media/meson/vdec/vdec.h b/drivers/staging/media/meson/vdec/vdec.h
index cc0cfafb8a951..d165c343fd022 100644
--- a/drivers/staging/media/meson/vdec/vdec.h
+++ b/drivers/staging/media/meson/vdec/vdec.h
@@ -67,6 +67,7 @@ struct amvdec_session;
* @v4l2_dev: v4l2 device
* @cur_sess: current decoding session
* @lock: video device lock
+ * @vdec_irq: irq for video decoding
*/
struct amvdec_core {
void __iomem *dos_base;
@@ -93,6 +94,7 @@ struct amvdec_core {
struct amvdec_session *cur_sess;
struct mutex lock;
+ int vdec_irq;
};
/**
--
2.50.1