On Wed Mar 4 09:35:06 2026 +0000, Fan Wu wrote:
> The fops_vcodec_release() function frees the context structure (ctx)
> without first cancelling any pending or running work in ctx->encode_work.
> This creates a race window where the workqueue handler (mtk_venc_worker)
> may still be accessing the context memory after it has been freed.
> 
> Race condition:
> 
>     CPU 0 (release path)               CPU 1 (workqueue)
>     ---------------------               ------------------
>     fops_vcodec_release()
>       v4l2_m2m_ctx_release()
>         v4l2_m2m_cancel_job()
>         // waits for m2m job "done"
>                                         mtk_venc_worker()
>                                           v4l2_m2m_job_finish()
>                                           // m2m job "done"
>                                           // BUT worker still running!
>                                           // post-job_finish access:
>                                         other ctx dereferences
>                                           // UAF if ctx already freed
>         // returns (job "done")
>       kfree(ctx)  // ctx freed
> 
> Root cause: The v4l2_m2m_ctx_release() only waits for the m2m job
> lifecycle (via TRANS_RUNNING flag), not the workqueue lifecycle.
> After v4l2_m2m_job_finish() is called, the m2m framework considers
> the job complete and v4l2_m2m_ctx_release() returns, but the worker
> function continues executing and may still access ctx.
> 
> The work is queued during encode operations via:
>   queue_work(ctx->dev->encode_workqueue, &ctx->encode_work)
> The worker function accesses ctx->m2m_ctx, ctx->dev, and other ctx
> fields even after calling v4l2_m2m_job_finish().
> 
> This vulnerability was confirmed with KASAN by running an instrumented
> test module that widens the post-job_finish race window. KASAN detected:
> 
>   BUG: KASAN: slab-use-after-free in mtk_venc_worker+0x159/0x180
>   Read of size 4 at addr ffff88800326e000 by task kworker/u8:0/12
> 
>   Workqueue: mtk_vcodec_enc_wq mtk_venc_worker
> 
>   Allocated by task 47:
>     __kasan_kmalloc+0x7f/0x90
>     fops_vcodec_open+0x85/0x1a0
> 
>   Freed by task 47:
>     __kasan_slab_free+0x43/0x70
>     kfree+0xee/0x3a0
>     fops_vcodec_release+0xb7/0x190
> 
> Fix this by calling cancel_work_sync(&ctx->encode_work) before kfree(ctx).
> This ensures the workqueue handler is both cancelled (if pending) and
> synchronized (waits for any running handler to complete) before the
> context is freed.
> 
> Placement rationale: The fix is placed after v4l2_ctrl_handler_free()
> and before list_del_init(&ctx->list). At this point, all m2m operations
> are done (v4l2_m2m_ctx_release() has returned), and we need to ensure
> the workqueue is synchronized before removing ctx from the list and
> freeing it.
> 
> Note: The open error path does NOT need cancel_work_sync() because
> INIT_WORK() only initializes the work structure - it does not schedule
> it. Work is only scheduled later during device_run() operations.
> 
> Fixes: 0934d3759615 ("media: mediatek: vcodec: separate decoder and encoder")
> Cc: [email protected]
> Signed-off-by: Fan Wu <[email protected]>
> Reviewed-by: Nicolas Dufresne <[email protected]>
> Signed-off-by: Nicolas Dufresne <[email protected]>
> Signed-off-by: Hans Verkuil <[email protected]>

Patch committed.

Thanks,
Hans Verkuil

 .../media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c  | 9 +++++++++
 1 file changed, 9 insertions(+)

---

diff --git 
a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c 
b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c
index c977ed0c09b6..4e4541b2fc8e 100644
--- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c
+++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c
@@ -215,6 +215,15 @@ static int fops_vcodec_release(struct file *file)
        v4l2_fh_exit(&ctx->fh);
        v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
 
+       /*
+        * Cancel any pending encode work before freeing the context.
+        * Although v4l2_m2m_ctx_release() waits for m2m job completion,
+        * the workqueue handler (mtk_venc_worker) may still be accessing
+        * the context after v4l2_m2m_job_finish() returns. Without this,
+        * a use-after-free occurs when the worker accesses ctx after kfree.
+        */
+       cancel_work_sync(&ctx->encode_work);
+
        spin_lock_irqsave(&dev->dev_ctx_lock, flags);
        list_del_init(&ctx->list);
        spin_unlock_irqrestore(&dev->dev_ctx_lock, flags);
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to