7.3-stable review patch. If anyone has any objections, please let me know. ------------------ From: Fan Wu commit 0f29f84317c1e35f6a9265277be33e60d3fc8c1c upstream. In vmalloc mode the frame-completion IRQ queues mcam_frame_work() on cam->s_bh_work, which memcpy()s from the dma_bufs[] that mcam_free_dma_bufs() frees with dma_free_coherent(). mccic_shutdown() frees those buffers without stopping the controller, so while streaming a late frame IRQ can re-arm the work after the buffers are gone, causing a use-after-free. Stop the controller in mccic_shutdown() when streaming is still active (gated on an open fd, which holds a runtime-PM reference, so the device is powered), cancel s_bh_work in mcam_free_dma_bufs(), and move INIT_WORK() into mccic_register() before the device can be published. Fixes: 67a8dbbc4e04 ("[media] marvell-cam: Basic working MMP camera driver") Cc: stable@vger.kernel.org Signed-off-by: Fan Wu Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/marvell/mcam-core.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) --- a/drivers/media/platform/marvell/mcam-core.c +++ b/drivers/media/platform/marvell/mcam-core.c @@ -406,6 +406,8 @@ static void mcam_free_dma_bufs(struct mc { int i; + cancel_work_sync(&cam->s_bh_work); + for (i = 0; i < cam->nbufs; i++) { dma_free_coherent(cam->dev, cam->dma_buf_size, cam->dma_bufs[i], cam->dma_handles[i]); @@ -1306,7 +1308,6 @@ static int mcam_setup_vb2(struct mcam_ca break; case B_vmalloc: #ifdef MCAM_MODE_VMALLOC - INIT_WORK(&cam->s_bh_work, mcam_frame_work); vq->ops = &mcam_vb2_ops; vq->mem_ops = &vb2_vmalloc_memops; cam->dma_setup = mcam_ctlr_dma_vmalloc; @@ -1864,6 +1865,12 @@ int mccic_register(struct mcam_camera *c goto out; } +#ifdef MCAM_MODE_VMALLOC + /* Init before sensor bind: armed by IRQ, cancelled on probe-error paths. */ + if (cam->buffer_mode == B_vmalloc) + INIT_WORK(&cam->s_bh_work, mcam_frame_work); +#endif + mutex_init(&cam->s_mutex); cam->state = S_NOTREADY; mcam_set_config_needed(cam, 1); @@ -1922,10 +1929,15 @@ void mccic_shutdown(struct mcam_camera * * take it down again will wedge the machine, which is frowned * upon. */ + mutex_lock(&cam->s_mutex); if (!list_empty(&cam->vdev.fh_list)) { cam_warn(cam, "Removing a device with users!\n"); + /* Stop so the IRQ can't re-arm s_bh_work after the buffers are freed. */ + if (cam->state == S_STREAMING) + mcam_ctlr_stop_dma(cam); sensor_call(cam, core, s_power, 0); } + mutex_unlock(&cam->s_mutex); if (cam->buffer_mode == B_vmalloc) mcam_free_dma_bufs(cam); v4l2_ctrl_handler_free(&cam->ctrl_handler);