During session teardown sequences in vdec_stop_streaming() and
vdec_close(), the 'esparser' hardware interrupt handler can still be
actively triggered or executing on another CPU core. This creates a
transient race condition where the ISR attempts to handle stream data and
allocate internal tracking state structures after session contexts have
been modified or freed.

Update esparser_isr() to read the current session context utilizing an
smp_load_acquire() barrier snapshot. If the pointer resolves to NULL,
terminate processing early with IRQ_HANDLED to protect against
concurrent dismantling.

Suggested-by: Doruk Tan Ozturk <[email protected]>
Reported-by: Sashiko <[email protected]>
Closes: https://lore.kernel.org/all/[email protected]/
Signed-off-by: Anand Moon <[email protected]>
---
 drivers/staging/media/meson/vdec/esparser.c | 8 ++++++++
 drivers/staging/media/meson/vdec/vdec.c     | 4 ++++
 drivers/staging/media/meson/vdec/vdec.h     | 2 ++
 3 files changed, 14 insertions(+)

diff --git a/drivers/staging/media/meson/vdec/esparser.c 
b/drivers/staging/media/meson/vdec/esparser.c
index 4632346f04a9e..37749ede308c6 100644
--- a/drivers/staging/media/meson/vdec/esparser.c
+++ b/drivers/staging/media/meson/vdec/esparser.c
@@ -60,6 +60,12 @@ static irqreturn_t esparser_isr(int irq, void *dev)
 {
        int int_status;
        struct amvdec_core *core = dev;
+       struct amvdec_session *sess;
+
+       /* Secure an atomic snapshot to protect against concurrent teardown */
+       sess = smp_load_acquire(&core->cur_sess);
+       if (!sess)
+               return IRQ_HANDLED;
 
        int_status = amvdec_read_parser(core, PARSER_INT_STATUS);
        amvdec_write_parser(core, PARSER_INT_STATUS, int_status);
@@ -439,6 +445,8 @@ int esparser_init(struct platform_device *pdev, struct 
amvdec_core *core)
        if (irq < 0)
                return irq;
 
+       core->esparser_irq = irq;
+
        ret = devm_request_irq(dev, irq, esparser_isr, IRQF_SHARED,
                               "esparserirq", core);
        if (ret) {
diff --git a/drivers/staging/media/meson/vdec/vdec.c 
b/drivers/staging/media/meson/vdec/vdec.c
index 7ae3d5a9dd6ab..7689ffdb2e500 100644
--- a/drivers/staging/media/meson/vdec/vdec.c
+++ b/drivers/staging/media/meson/vdec/vdec.c
@@ -486,6 +486,8 @@ static void vdec_stop_streaming(struct vb2_queue *q)
 
                /* Synchronize and flush pending hardware interrupt service 
routines */
                synchronize_irq(core->vdec_irq);
+               /* Ensure esparser ISR finishes executing */
+               synchronize_irq(core->esparser_irq);
 
                vdec_poweroff(sess);
                vdec_free_canvas(sess);
@@ -994,6 +996,8 @@ static int vdec_close(struct file *file)
 
        /* Synchronize and flush pending hardware interrupt service routines */
        synchronize_irq(core->vdec_irq);
+       /* Ensure esparser ISR finishes executing */
+       synchronize_irq(core->esparser_irq);
 
        if (!IS_ERR_OR_NULL(sess->recycle_thread)) {
                kthread_stop(sess->recycle_thread);
diff --git a/drivers/staging/media/meson/vdec/vdec.h 
b/drivers/staging/media/meson/vdec/vdec.h
index d165c343fd022..c4639cf33e73e 100644
--- a/drivers/staging/media/meson/vdec/vdec.h
+++ b/drivers/staging/media/meson/vdec/vdec.h
@@ -68,6 +68,7 @@ struct amvdec_session;
  * @cur_sess: current decoding session
  * @lock: video device lock
  * @vdec_irq: irq for video decoding
+ * @esparser_irq: irq for elementary stream parsing
  */
 struct amvdec_core {
        void __iomem *dos_base;
@@ -95,6 +96,7 @@ struct amvdec_core {
        struct amvdec_session *cur_sess;
        struct mutex lock;
        int vdec_irq;
+       int esparser_irq;
 };
 
 /**
-- 
2.50.1

Reply via email to