Linux kernel and device drivers for NXP i.MX platforms
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Guangshuo Li" <liguangshuo@mail.sdu.edu.cn>
Cc: imx@lists.linux.dev, Frank.Li@kernel.org, media-ci@linuxtv.org
Subject: Re: [PATCH] media: nxp: imx8-isi: Fix potential pipe leaks on removal
Date: Sat, 07 Nov 2026 07:13:20 +0000	[thread overview]
Message-ID: <sashiko-outbox-202678@kernel.org> (raw)
In-Reply-To: <20261107-0d0c29e10a-media-imx8-isi-1@mail.sdu.edu.cn>

Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Medium] media: nxp: imx8-isi: NULL deref on
  media_device_register_entity() error
It also noticed 2 related pre-existing issues this patch does not
introduce:
- [Medium] media: nxp: imx8-isi: stateless device link leak in
  mxc_isi_async_notifier_bound() [1]
- [Critical] media: nxp: imx8-isi: unchecked dma_set_mask_and_coherent()
  in mxc_isi_probe() [2]
--

commit 1c93ad5a0d826cfb633314a1db34b0975979e67c
Author: Guangshuo Li <liguangshuo@mail.sdu.edu.cn>

media: nxp: imx8-isi: Fix potential pipe leaks on removal

This commit refcounts mxc_isi_dev so that pipe and V4L2 state stays alive
until both device removal and the last V4L2 reference complete, while
disconnecting capture and M2M queues during unregistration.

> diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
> index 0ae5f35e017c6..bd046a0751b9f 100644
> --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
> +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c

[ ... ]

> @@ -211,33 +256,25 @@ static int mxc_isi_v4l2_init(struct mxc_isi_dev *isi)
>  	return 0;
>  
>  err_m2m:
> -	mxc_isi_m2m_unregister(isi);
>  	v4l2_async_nf_cleanup(&isi->notifier);
>  err_v4l2:
> +	mxc_isi_video_unregister_all(isi);
>  	v4l2_device_unregister(v4l2_dev);
> +	media_device_unregister(media_dev);
> +	v4l2_device_put(v4l2_dev);
>  err_media:
> -	media_device_cleanup(media_dev);
>  	return ret;
>  }
>  
>  static void mxc_isi_v4l2_cleanup(struct mxc_isi_dev *isi)
>  {
> -	unsigned int i;
> +	mxc_isi_video_unregister_all(isi);
>  
>  	v4l2_async_nf_unregister(&isi->notifier);
>  	v4l2_async_nf_cleanup(&isi->notifier);
> -
>  	v4l2_device_unregister(&isi->v4l2_dev);
>  	media_device_unregister(&isi->media_dev);
> -
> -	mxc_isi_m2m_unregister(isi);
> -
> -	for (i = 0; i < isi->pdata->num_channels; ++i)
> -		mxc_isi_pipe_unregister(&isi->pipes[i]);
> -
> -	mxc_isi_crossbar_unregister(&isi->crossbar);
> -
> -	media_device_cleanup(&isi->media_dev);
> +	v4l2_device_put(&isi->v4l2_dev);
>  }

[Severity: Medium]
This problem wasn't introduced by this patch, but does the driver leak the
stateless device link created in mxc_isi_async_notifier_bound() [1]?

drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c:mxc_isi_async_notifier_bound() {
	...
	link = device_link_add(isi->dev, sd->dev, DL_FLAG_STATELESS);
	if (!link) {
		dev_err(isi->dev,
			"Failed to create device link to source %s\n", sd->name);
		return -EINVAL;
	}

	return v4l2_create_fwnode_links_to_pad(sd, pad, link_flags);
}

Because DL_FLAG_STATELESS is used, the driver core does not remove the link
automatically.  If v4l2_create_fwnode_links_to_pad() fails, or when a
subdevice unbinds or the ISI driver is removed (since
mxc_isi_async_notifier_ops has no .unbind callback and
mxc_isi_v4l2_cleanup() does not delete the link), the device_link and its
device references are leaked, and repeated subdevice unbind/rebind cycles
increment the link's refcount indefinitely.

> @@ -479,11 +516,15 @@ static int mxc_isi_probe(struct platform_device *pdev)
>  	unsigned int i;
>  	int ret = 0;
>  
> -	isi = devm_kzalloc(dev, sizeof(*isi), GFP_KERNEL);
> +	isi = kzalloc_obj(*isi);
>  	if (!isi)
>  		return -ENOMEM;
>  
> -	isi->dev = dev;
> +	isi->dev = get_device(dev);
> +	kref_init(&isi->ref);
> +	ret = devm_add_action_or_reset(dev, mxc_isi_put, isi);
> +	if (ret)
> +		return ret;
>  	platform_set_drvdata(pdev, isi);
>  
>  	isi->pdata = of_device_get_match_data(dev);
> @@ -521,48 +562,35 @@ static int mxc_isi_probe(struct platform_device *pdev)
>  		return dev_err_probe(dev, ret,
>  				     "Failed to initialize crossbar\n");

[Severity: Critical]
This problem wasn't introduced by this patch, but should mxc_isi_probe()
check the return value of dma_set_mask_and_coherent() [2]?

drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c:mxc_isi_probe() {
	...
	dma_size = isi->pdata->has_36bit_dma ? 36 : 32;
	dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_size));

	ret = devm_pm_runtime_enable(dev);
	...
}

If setting the 32-bit or 36-bit DMA mask fails, probe continues with an
invalid DMA configuration, which can truncate physical addresses during DMA
transfers and cause memory corruption or IOMMU faults.

[ ... ]

> diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c
> index b729eecad0fef..5349e09e9b57a 100644
> --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c
> +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c

[ ... ]

> @@ -790,11 +801,11 @@ int mxc_isi_m2m_register(struct mxc_isi_dev *isi, struct v4l2_device *v4l2_dev)
>  	vdev->entity.function = MEDIA_ENT_F_IO_V4L;
>  	ret = media_entity_pads_init(&vdev->entity, 1, &m2m->pad);
>  	if (ret)
> -		goto err_video;
> +		goto err_unregister;
>  
>  	ret = media_device_register_entity(v4l2_dev->mdev, &vdev->entity);
>  	if (ret)
> -		goto err_entity_cleanup;
> +		goto err_unregister;

[ ... ]

>  err_unregister:
> +	mxc_isi_m2m_unregister(isi);
> +err_return:
>  	return ret;
>  }
>  
> @@ -849,13 +851,43 @@ int mxc_isi_m2m_unregister(struct mxc_isi_dev *isi)
>  {
>  	struct mxc_isi_m2m *m2m = &isi->m2m;
>  	struct video_device *vdev = &m2m->vdev;
> +	struct mxc_isi_m2m_ctx *ctx;
>  
> +	if (!video_is_registered(vdev))
> +		return 0;
> +
> +	guard(mutex)(&m2m->contexts_lock);
>  	video_unregister_device(vdev);
> +	v4l2_m2m_suspend(m2m->m2m_dev);
> +	list_for_each_entry(ctx, &m2m->contexts, list) {
> +		guard(mutex)(&ctx->vb2_lock);
> +		vb2_queue_error(v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx));
> +		vb2_queue_error(v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx));
> +		v4l2_m2m_streamoff(NULL, ctx->fh.m2m_ctx,
> +				   V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
> +		v4l2_m2m_streamoff(NULL, ctx->fh.m2m_ctx,
> +				   V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
> +	}
>  
> -	v4l2_m2m_release(m2m->m2m_dev);
> -	media_devnode_remove(m2m->intf);
> -	media_entity_cleanup(&vdev->entity);
> -	mutex_destroy(&m2m->lock);
> +	if (m2m->intf) {
> +		media_devnode_remove(m2m->intf);
> +		m2m->intf = NULL;
> +	}
> +	media_device_unregister_entity(&vdev->entity);

[Severity: Medium]
Can jumping to err_unregister when media_device_register_entity() fails
cause a NULL pointer dereference in media_device_unregister_entity()?

drivers/media/mc/mc-device.c:media_device_register_entity() {
	...
	entity->graph_obj.mdev = mdev;
	INIT_LIST_HEAD(&entity->links);
	entity->num_links = 0;
	entity->num_backlinks = 0;

	ret = ida_alloc_min(&mdev->entity_internal_idx, 1, GFP_KERNEL);
	if (ret < 0)
		return ret;
	...
}

If ida_alloc_min() fails inside media_device_register_entity(),
entity->graph_obj.mdev is already set, while entity->internal_idx is still 0
and media_gobj_create() has not initialized entity->graph_obj.list.
Calling mxc_isi_m2m_unregister() -> media_device_unregister_entity() on this
partially initialized entity then calls ida_free() on index 0 and
list_del(&gobj->list) on a zeroed list_head, dereferencing NULL.

[1] https://sashiko.dev/#/bug/linux-feae4a20-e500-4215-90d3-b1654008ecd5
[2] https://sashiko.dev/#/bug/linux-939c7345-a73b-4e71-844e-5708e3fa78c4

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261107-0d0c29e10a-media-imx8-isi-1@mail.sdu.edu.cn?part=1

  reply	other threads:[~2026-11-07  7:13 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-07  6:54 [PATCH] media: nxp: imx8-isi: Fix potential pipe leaks on removal Guangshuo Li
2026-11-07  7:13 ` sashiko-bot [this message]
2026-11-07 11:01 ` Laurent Pinchart

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-202678@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=Frank.Li@kernel.org \
    --cc=imx@lists.linux.dev \
    --cc=liguangshuo@mail.sdu.edu.cn \
    --cc=media-ci@linuxtv.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox