The hard interrupt handler (vdec_isr) and the threaded interrupt handler
(vdec_threaded_isr) directly read core->cur_sess without synchronization
or validation. If a streaming teardown concurrently clears core->cur_sess
to NULL while an interrupt is being processed, a NULL pointer dereference
occurs when accessing the session fields or codec operations.

Fix this race condition by using READ_ONCE() to obtain a stable, atomic
snapshot of core->cur_sess. Check if the returned session pointer is NULL,
and return IRQ_NONE immediately if the session has already been torn down.

Cc: Nicolas Dufresne <[email protected]>
Reported-by: Sashiko <[email protected]>
Closes: https://lore.kernel.org/all/[email protected]/
Fixes: 3e7f51bd9607 ("media: meson: add v4l2 m2m video decoder driver")
Signed-off-by: Anand Moon <[email protected]>
---
 drivers/staging/media/meson/vdec/vdec.c | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/media/meson/vdec/vdec.c 
b/drivers/staging/media/meson/vdec/vdec.c
index f99335effe17..3897c75b19c8 100644
--- a/drivers/staging/media/meson/vdec/vdec.c
+++ b/drivers/staging/media/meson/vdec/vdec.c
@@ -996,17 +996,36 @@ 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;
+       irqreturn_t ret = IRQ_HANDLED;
+
+       /*
+        * Use READ_ONCE to secure an atomic snapshot of the pointer,
+        * protecting against concurrent clearing during streaming
+        * teardowns.
+        */
+       sess = READ_ONCE(core->cur_sess);
+       if (!sess)
+               return IRQ_NONE;
 
        sess->last_irq_jiffies = get_jiffies_64();
+       ret = sess->fmt_out->codec_ops->isr(sess);
 
-       return sess->fmt_out->codec_ops->isr(sess);
+       return ret;
 }
 
 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 = READ_ONCE(core->cur_sess);
+       if (!sess)
+               return IRQ_NONE;
 
        return sess->fmt_out->codec_ops->threaded_isr(sess);
 }
-- 
2.50.1

Reply via email to