summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFan Wu <fanwu01@zju.edu.cn>2026-06-23 10:30:31 +0000
committerHans Verkuil <hverkuil+cisco@kernel.org>2026-08-31 08:58:50 +0200
commit78fdfbf117c409273eecbfa7a528ef42358a0e38 (patch)
tree9d8e9875947bad579535341237904886e98ea781
parent37d020b109a977aff6ab30b1ea19d70ffe1d76c6 (diff)
downloadlinux-next-78fdfbf117c409273eecbfa7a528ef42358a0e38.tar.gz
linux-next-78fdfbf117c409273eecbfa7a528ef42358a0e38.zip
media: imx-jpeg: cancel timeout worker when streaming stops
Each per-fd context ctx owns a delayed_work (ctx->task_timer, callback mxc_jpeg_device_run_timeout) armed via schedule_delayed_work() at the end of mxc_jpeg_device_run() to recover a stalled encode/decode job. The only existing cancellation is cancel_delayed_work() in the frame-done IRQ handler, which de-queues a pending work item but does not wait for a callback that has already started, and it only runs when a frame completes. When the fd is closed while a job is in flight (the frame-done IRQ has not fired yet), nothing syncs the worker before mxc_jpeg_release() frees ctx with kfree() after v4l2_m2m_ctx_release(). A queued or executing mxc_jpeg_device_run_timeout() can then recover ctx through container_of(&ctx->task_timer) and dereference it (ctx->mxc_jpeg, slot_data, dev_warn) after ctx has been freed. Cancel the worker from mxc_jpeg_stop_streaming(). The cancel cannot live in mxc_jpeg_release(): mxc_jpeg_device_run() arms the timer while holding only hw_lock, not the mxc_jpeg->lock mutex that release holds, so a cancel in release could still race a concurrent mxc_jpeg_device_run() that re-arms the timer afterwards. mxc_jpeg_stop_streaming() instead runs inside v4l2_m2m_ctx_release() -> vb2_queue_release(), i.e. after v4l2_m2m_cancel_job() has set TRANS_ABORT and waited for any in-flight job to finish (so __v4l2_m2m_try_queue() will not queue and v4l2_m2m_try_run() will not run any further job for this context, which prevents mxc_jpeg_device_run() from re-arming the timer) and before the m2m context is freed. cancel_delayed_work_sync() removes a pending work item and waits for a running callback, so the worker can no longer race with the subsequent kfree(). The cancel is placed before the buffer-release loop so a concurrently running timeout callback cannot race with it over the same buffers. If the frame-done IRQ canceled a still-pending timer, this cancel is a no-op; if the timeout callback has already started, it waits for the callback to finish. The same mxc_jpeg_stop_streaming() call is also reached from VIDIOC_STREAMOFF, which drains the worker early, although STREAMOFF itself does not free ctx -- the use-after-free arises only when the fd is later closed. This bug was found by static analysis. Fixes: cfed9632ca8e ("media: imx-jpeg: Add a timeout mechanism for each frame") Cc: stable@vger.kernel.org Signed-off-by: Fan Wu <fanwu01@zju.edu.cn> Reviewed-by: Ming Qian <ming.qian@oss.nxp.com> Signed-off-by: Frank Li <Frank.Li@nxp.com> Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
index 725e94152884..ea2fad5dd646 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
@@ -1798,6 +1798,8 @@ static void mxc_jpeg_stop_streaming(struct vb2_queue *q)
dev_dbg(ctx->mxc_jpeg->dev, "Stop streaming ctx=%p", ctx);
+ cancel_delayed_work_sync(&ctx->task_timer);
+
/* Release all active buffers */
for (;;) {
if (V4L2_TYPE_IS_OUTPUT(q->type))