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
