Devicetree
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Antoine Bouyer" <antoine.bouyer@nxp.com>
Cc: imx@lists.linux.dev, conor+dt@kernel.org, krzk+dt@kernel.org,
	Frank.Li@kernel.org, robh@kernel.org, devicetree@vger.kernel.org
Subject: Re: [PATCH v2 6/8] media: platform: Add NXP Neoisp Image Signal Processor
Date: Tue, 12 May 2026 05:29:09 +0000	[thread overview]
Message-ID: <20260512052910.40B44C2BCB0@smtp.kernel.org> (raw)
In-Reply-To: <20260511132629.1300868-7-antoine.bouyer@nxp.com>

Thank you for your contribution! Sashiko AI review found 13 potential issue(s) to consider:
- [Critical] Concurrency / List Corruption in `neoisp_prepare_job` due to lockless `ready_queue` access.
- [Critical] TOCTOU in userspace parameters buffer leading to Arbitrary Code Execution.
- [Critical] Typo in `NEOISP_COLORSPACE_MASK` (`&&` instead of `&`) leading to Out-of-Bounds Read.
- [High] Incorrect standard `memcpy()` used for `__iomem` regions.
- [High] Stale buffer pointers in `queued_job.buf` leading to Double-Completion and Use-After-Free.
- [High] Double `v4l2_device_unregister` in `neoisp_init_devices` error path.
- [High] Use-After-Free due to incorrect teardown order in `neoisp_destroy_devices()`.
- [High] Asynchronous Runtime PM suspend is cancelled during device removal, leaving hardware powered on.
- [High] Unprotected hardware access in the IRQ handler while the device may be suspended.
- [High] HDR mode bits are not disabled when `INPUT1_NODE` stops streaming.
- [High] Unchecked `get_vaddr()` return value leads to NULL pointer dereference.
- [Medium] Missing `HAS_DMA` dependency in Kconfig for `VIDEOBUF2_DMA_CONTIG`.
- [Low] Unconditional assignment of `dev_pm_ops` structure creates dead code.
--

commit 6a87cbbdaa6c05a70269ebaa1a23189afb0ffe0f
Author: Antoine Bouyer <antoine.bouyer@nxp.com>
Subject: media: platform: Add NXP Neoisp Image Signal Processor

This commit introduces the NXP Neoisp driver to support 8-16 bit RAW Bayer,
monochrome, and generic v4l2-isp formats. It features a standalone module
parameter, supports generic v4l2-isp parameters and statistics, and handles
context sharing across multiple V4L2 nodes.

> diff --git a/drivers/media/platform/nxp/neoisp/Kconfig b/drivers/media/platform/nxp/neoisp/Kconfig
> --- /dev/null
> +++ b/drivers/media/platform/nxp/neoisp/Kconfig
> @@ -0,0 +1,16 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +
> +config VIDEO_NXP_NEOISP
> +	tristate "NXP NEO Image Signal Processor (ISP) driver"
> +	depends on VIDEO_DEV
> +        depends on ARCH_MXC || COMPILE_TEST
> +	select MEDIA_CONTROLLER
> +	select VIDEOBUF2_DMA_CONTIG

Will selecting VIDEOBUF2_DMA_CONTIG on architectures lacking HAS_DMA when
COMPILE_TEST is enabled result in unmet Kconfig dependency warnings and build
failures?

> diff --git a/drivers/media/platform/nxp/neoisp/neoisp.h b/drivers/media/platform/nxp/neoisp/neoisp.h
> --- /dev/null
> +++ b/drivers/media/platform/nxp/neoisp/neoisp.h
[ ... ]
> +#define NEOISP_COLORSPACE_MASK(colorspace) BIT((colorspace) && 0x1f)

Is it possible this intended to use a bitwise AND instead of a logical AND?

Using && evaluates to BIT(1) for any non-zero colorspace, which could render
the validation in neoisp_try_fmt() ineffective. If userspace requests an
unsupported colorspace, could this cause the xfer and enc indices to exceed
the bounds of xfer_lut and enc_lut during hardware programming?

> diff --git a/drivers/media/platform/nxp/neoisp/neoisp_ctx.c b/drivers/media/platform/nxp/neoisp/neoisp_ctx.c
> --- /dev/null
> +++ b/drivers/media/platform/nxp/neoisp/neoisp_ctx.c
[ ... ]
> +static inline void ctx_blk_write(enum isp_block_map_e map, u32 *ptr, u32 *dest)
> +{
[ ... ]
> +	memcpy(dest + woffset, ptr, count);
> +}

Is it safe to use standard memcpy() on __iomem regions here, and similarly
in neoisp_ctx_upload_context() and neoisp_ctx_get_stats_blk()?

On ARM64 architectures, executing standard memory instructions against Device
memory might generate synchronous external aborts. Should this use
memcpy_toio() and memcpy_fromio() instead?

> +void neoisp_ctx_update_w_user_params(struct neoisp_dev_s *neoispd)
> +{
[ ... ]
> +	params = (struct v4l2_isp_buffer *)get_vaddr(buf);
> +
> +	if (params->data_size == 0)

Can get_vaddr() return NULL for unmapped DMABUF buffers?

If so, does dereferencing params->data_size here unconditionally lead to a
NULL pointer dereference?

> +	while (block_offset < max_offset) {
> +		union neoisp_params_block_u *block = (union neoisp_params_block_u *)
> +			&params->data[block_offset];
> +		block_offset += block->header.size;
> +
> +		block_handler = &neoisp_block_handlers[block->header.type];
> +		block_handler->handler(neoispd->context, block);
> +	}

Is this vulnerable to a Time-Of-Check-to-Time-Of-Use (TOCTOU) race condition?

Since the buffer can be modified by userspace concurrently after the initial
QBUF validation, could a malicious thread alter the block->header.type field
to an out-of-bounds value and force the driver to execute an arbitrary function
pointer?

> +void neoisp_ctx_update_hdr_mode(struct neoisp_dev_s *neoispd,
> +				struct neoisp_context_s *context)
> +{
> +	struct neoisp_hdr_merge_s *hmg = &context->hw.hdr_merge;
> +	struct neoisp_hdr_decompress1_s *hd1 = &context->hw.hdr_decompress1;
> +
> +	hmg->ctrl |= NEO_HDR_MERGE_CTRL_CAM0_ENABLE;
> +	hd1->ctrl |= NEO_HDR_DECOMPRESS1_CTRL_CAM0_ENABLE;
> +}

Does the driver ever disable these HDR mode bits when INPUT1_NODE stops
streaming?

If INPUT0_NODE continues streaming without INPUT1_NODE, could the hardware
remain in an invalid HDR mode and attempt to read from a zeroed DMA address?

> diff --git a/drivers/media/platform/nxp/neoisp/neoisp_main.c b/drivers/media/platform/nxp/neoisp/neoisp_main.c
> --- /dev/null
> +++ b/drivers/media/platform/nxp/neoisp/neoisp_main.c
[ ... ]
> +static int neoisp_prepare_job(struct neoisp_dev_s *neoispd)
> +{
[ ... ]
> +	for (i = 0; i < NEOISP_NODES_COUNT; i++) {
> +		if (buf[i]) {
> +			list_del(&buf[i]->ready_list);
> +			job->buffers[i] = buf[i];
> +		}
> +	}

Are we iterating and removing items from the ready_queue across multiple nodes
without holding a cross-node or global lock?

Since neoisp_node_buf_queue() inserts buffers into these lists using only a
per-node queue_lock, could concurrent QBUF calls lead to list corruption here?

> +static irqreturn_t neoisp_irq_handler(int irq, void *dev_id)
> +{
[ ... ]
> +	irq_status = neoisp_rd(neoispd, NEO_PIPE_CONF_INT_STAT0);

Can this interrupt handler run while the hardware is in a suspended Runtime PM
state?

If a shared or spurious interrupt fires, could accessing
NEO_PIPE_CONF_INT_STAT0 without calling pm_runtime_get_if_active() result in
a bus hang or invalid read?

[ ... ]
> +	if (done) {
> +		for (i = 0; i < NEOISP_NODES_COUNT; i++) {
> +			if (buf[i]) {
> +				buf[i]->vb.sequence = neoispd->frame_sequence;
> +				buf[i]->vb.vb2_buf.timestamp = ts;
> +				vb2_buffer_done(&buf[i]->vb.vb2_buf, VB2_BUF_STATE_DONE);
> +			}
> +		}

Should the completed buffer pointers in neoispd->queued_job.buf be cleared
here?

If a subsequent spurious or late error interrupt fires and sets done = true
before a new job is scheduled, could the handler invoke vb2_buffer_done()
again on the same buffer pointers, causing a use-after-free?

> +static void neoisp_destroy_devices(struct neoisp_dev_s *neoispd)
> +{
[ ... ]
> +	if (neoispd->context) {
> +		dma_free_coherent(neoispd->dev,
> +				  sizeof(struct neoisp_context_s),
> +				  neoispd->context,
> +				  neoispd->params_dma_addr);
> +	}
[ ... ]
> +	for (i = NEOISP_NODES_COUNT - 1; i >= 0; i--) {
> +		video_unregister_device(&neoispd->node[i].vfd);
> +		vb2_queue_release(&neoispd->node[i].queue);
> +	}
> +}

Is it possible for a use-after-free to occur here?

Releasing the queues calls neoisp_node_stop_streaming(), which calls
neoisp_set_default_context(). That function performs a memcpy() into
neoispd->context, but neoispd->context has already been freed by
dma_free_coherent() earlier in this function.

> +static int neoisp_init_devices(struct neoisp_dev_s *neoispd)
> +{
[ ... ]
> +	ret = media_device_register(mdev);
> +	if (ret)
> +		goto err_media;
> +
> +	return 0;
> +
> +err_media:
> +	neoisp_destroy_devices(neoispd);
> +err_group:
> +	media_device_cleanup(&neoispd->mdev);
> +err_unregister_v4l2:
> +	v4l2_device_unregister(v4l2_dev);
> +	return ret;
> +}

Does this error path unregister the V4L2 device twice?

neoisp_destroy_devices() internally calls v4l2_device_unregister() on
&neoispd->v4l2_dev, and execution then falls through to err_unregister_v4l2,
calling it again.

> +static void neoisp_remove(struct platform_device *pdev)
> +{
[ ... ]
> +	pm_runtime_dont_use_autosuspend(neoispd->dev);
> +	pm_runtime_disable(neoispd->dev);
> +}

Could this leave the hardware powered on indefinitely?

If there are asynchronous suspend requests queued (for instance, via
pm_runtime_put_autosuspend() during vb2_queue_release()), calling
pm_runtime_disable() immediately will cancel those pending idle/suspend work
tasks.

> +static struct platform_driver neoisp_driver = {
> +	.probe  = neoisp_probe,
> +	.remove = neoisp_remove,
> +	.driver = {
> +		.name = NEOISP_NAME,
> +		.pm = &neoisp_pm,
> +		.of_match_table = neoisp_dt_ids,
> +	},
> +};

Should the .pm assignment be wrapped with pm_ptr()?

If CONFIG_PM is disabled, the unconditional reference to neoisp_pm will cause
it and all its callbacks to be compiled into the kernel as dead code.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260511132629.1300868-1-antoine.bouyer@nxp.com?part=6

  parent reply	other threads:[~2026-05-12  5:29 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-11 13:26 [PATCH v2 0/8] media: Add iMX95 neoisp driver Antoine Bouyer
2026-05-11 13:26 ` [PATCH v2 1/8] dt-bindings: media: Add nxp neoisp support Antoine Bouyer
2026-05-11 16:26   ` Conor Dooley
2026-05-11 13:26 ` [PATCH v2 2/8] media: v4l2-ctrls: Add user control base for NXP neoisp controls Antoine Bouyer
2026-05-11 13:26 ` [PATCH v2 3/8] media: Add meta formats supported by NXP neoisp driver Antoine Bouyer
2026-05-11 13:26 ` [PATCH v2 4/8] media: uapi: Add NXP NEOISP user interface header file Antoine Bouyer
2026-05-12  4:47   ` sashiko-bot
2026-05-11 13:26 ` [PATCH v2 5/8] media: Documentation: Add NXP neoisp driver documentation Antoine Bouyer
2026-05-12  5:04   ` sashiko-bot
2026-05-11 13:26 ` [PATCH v2 6/8] media: platform: Add NXP Neoisp Image Signal Processor Antoine Bouyer
2026-05-11 14:43   ` Antoine Bouyer
2026-05-12  5:29   ` sashiko-bot [this message]
2026-05-11 13:26 ` [PATCH v2 7/8] media: platform: neoisp: Add debugfs support Antoine Bouyer
2026-05-12  5:47   ` sashiko-bot
2026-05-11 13:26 ` [PATCH v2 8/8] arm64: dts: freescale: imx95: Add NXP neoisp device tree node Antoine Bouyer

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=20260512052910.40B44C2BCB0@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=Frank.Li@kernel.org \
    --cc=antoine.bouyer@nxp.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=imx@lists.linux.dev \
    --cc=krzk+dt@kernel.org \
    --cc=robh@kernel.org \
    --cc=sashiko@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