Devicetree
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: pankaj.gupta@oss.nxp.com
Cc: robh@kernel.org, conor+dt@kernel.org, imx@lists.linux.dev,
	devicetree@vger.kernel.org, Frank.Li@kernel.org
Subject: Re: [PATCH v43 5/7] firmware: imx: adds miscdev
Date: Mon, 31 Aug 2026 07:05:07 +0000	[thread overview]
Message-ID: <20260831070508.252E01F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260831-imx-se-if-v43-5-a3deadbda4ef@nxp.com>

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] The SE_IOCTL_ENABLE_CMD_RCV_STATUS ioctl fails to actually register and arm the command receiver, effectively breaking the ioctl's functionality.
- [High] Bypassing the user-provided buffer size when validating the firmware response causes out-of-bounds reads on the rx_msg allocation and fails to capture the handle.
- [High] The `priv->modify_lock` and `priv->se_if_cmd_lock` mutexes are accessed after being destroyed by devres on device unbind, leading to a Use-After-Free of mutex state.
- [High] Hardware out-of-bounds read via missing DMA buffer size boundary checks for variable-length input buffers.
- [High] Unbounded DMA coherent memory allocation in `se_if_fops_open()` allows userspace to exhaust CMA/DMA pools.
- [Medium] The `se_if_probe` function leaks the `priv` structure and a `struct device` reference if `devm_mutex_init` fails.
--

commit b9f90d072db22d668c690d048d2cb3e33090c742
Author: Pankaj Gupta <pankaj.gupta@nxp.com>
Subject: firmware: imx: adds miscdev

This commit adds a character driver to enable exchanging messages with the
NXP secure enclave hardware from userspace. It introduces ABI definitions
and base API checks to block arbitrary command exchanges.

> diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
> --- a/drivers/firmware/imx/se_ctrl.c
> +++ b/drivers/firmware/imx/se_ctrl.c
[ ... ]
> +		switch (cmd) {
> +		case SE_IOCTL_ENABLE_CMD_RCV_STATUS: {
> +			guard(mutex)(&priv->modify_lock);
> +			err = check_cmd_rcvr_status(dev_ctx);
> +			if (err)
> +				dev_err(priv->dev, "Failed[%ld] to register %s as CMD-Receiver.\n",
> +					err, dev_ctx->devname);
> +		break;
> +		}

[Severity: High]
Is it intentional that se_ioctl() only checks the status here but does not
actually perform the registration? 

It appears set_dev_ctx_as_command_receiver() is never called, causing the
ioctl to fail its intended purpose and always return -ENXIO if not already
registered.

[ ... ]
> +static int se_ioctl_cmd_snd_rcv_rsp_handler(struct se_if_device_ctx *dev_ctx,
> +					    void __user *uarg)
> +{
[ ... ]
> +	rsp_status_err =
> +		se_val_rsp_hdr_n_status(priv, rx_msg, tx_msg->header.command,
> +					rx_msg->header.size << 2,
> +					tx_msg->header.ver == priv->if_defs->base_api_ver);

[Severity: High]
Could passing the firmware-declared size (rx_msg->header.size << 2) instead of
the caller's allocated size (rx_buf_sz) lead to out-of-bounds reads? 

If a user submits an intentionally small rx_buf_sz, the subsequent validation
in se_val_rsp_hdr_n_status() and fw_api_specific_ops() might read past the
bounds of the allocated rx_msg buffer when accessing data[0] or data[1].

[ ... ]
> +static int se_if_probe(struct platform_device *pdev)
> +{
[ ... ]
> +	ret = devm_mutex_init(dev, &priv->se_if_cmd_lock);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "Failed to init mutex: priv se_if_cmd_lock.\n");
> +	ret = devm_mutex_init(dev, &priv->modify_lock);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "Failed to init mutex: priv modify_lock.\n");

[Severity: High]
Does binding the lifecycle of these mutexes to device unbind create a 
use-after-free risk? 

Since priv is refcounted and can outlive device unbind (e.g., if a file 
descriptor remains open), closing the file later calls dlink_n_cleanup_dev_ctx()
and cleanup_dev_ctx(), which will attempt to acquire these destroyed mutexes.

[ ... ]
> +static int se_if_probe(struct platform_device *pdev)
> +{
[ ... ]
> +	priv = kzalloc_obj(*priv);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = dev;
> +	/*
> +	 * Pin the parent device for the lifetime of priv. A file descriptor may
> +	 * stay open after the device is unbound; close() then still passes
> +	 * priv->dev to dma_free_coherent()/dev_warn(). Without this reference
> +	 * the struct device could be freed while priv->dev still points at it,
> +	 * so the reference is dropped in se_if_priv_release() via put_device().
> +	 */
> +	get_device(priv->dev);
> +	kref_init(&priv->refcount);
> +	priv->if_defs = &if_node->if_defs;
> +	dev_set_drvdata(dev, priv);
> +
[ ... ]
> +	ret = devm_mutex_init(dev, &priv->se_if_cmd_lock);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "Failed to init mutex: priv se_if_cmd_lock.\n");

[Severity: Medium]
If devm_mutex_init() fails, does this function return directly without
cleaning up? 

It appears this would leak the priv structure and leave the device reference
unreleased, since devm_add_action_or_reset() has not been registered yet.

[ ... ]
> +static int se_if_fops_open(struct inode *nd, struct file *fp)
> +{
[ ... ]
> +	priv->dev_ctx_mono_count++;
> +	err = init_device_context(priv, priv->dev_ctx_mono_count, &dev_ctx);
> +	if (err) {
> +		dev_err(priv->dev, "Failed to create dev-ctx.\n");
> +		goto out_unlock_misc;
> +	}

> +static int init_se_shared_mem(struct se_if_device_ctx *dev_ctx)
> +{
[ ... ]
> +	se_shared_mem_mgmt->non_secure_mem.ptr =
> +			dma_alloc_coherent(priv->dev, MAX_DATA_SIZE_PER_USER,
> +					   &se_shared_mem_mgmt->non_secure_mem.dma_addr,
> +					   GFP_KERNEL);

[Severity: High]
Does this code allow unbounded DMA coherent memory allocation? 

If a userspace process repeatedly calls open() in a loop, it seems it would 
allocate 128KB each time without any limit, which could quickly exhaust 
contiguous DMA memory.

> diff --git a/drivers/firmware/imx/ele_msg_addr_field.c b/drivers/firmware/imx/ele_msg_addr_field.c
> --- a/drivers/firmware/imx/ele_msg_addr_field.c
> +++ b/drivers/firmware/imx/ele_msg_addr_field.c
[ ... ]
> +static const struct se_cmd_addr_field ele_oem_auth_cntr_addr_fields[] = {
> +	/*
> +	 * Container Header address: a 64-bit physical address split across two
> +	 * words. data[0] holds the 32-bit MSB and data[1] holds the 32-bit LSB
> +	 * (ELE API spec Table 27, word size = 0x3, so the command is header +
> +	 * MSB + LSB only). The message carries no length word for this buffer;
> +	 * the container size is variable and not communicated in the MU payload,
> +	 * and no static firmware-defined maximum is specified. Because this is a
> +	 * read-only input buffer (the ELE ROM/FW copies the container header
> +	 * into its internal memory for authentication and does not write back
> +	 * through this address), enforcing only the start-address range check is
> +	 * acceptable: a rogue caller can at most cause firmware to read within
> +	 * the shared-memory window, which is memory the caller already owns.
> +	 * Output buffers must be fully bounded; input-only buffers are safe with
> +	 * addr-only checks.
> +	 */
> +	{ .lsb_idx = 1, .msb_idx = 0, .has_msb = true, .flag_idx = SE_CMD_ADDR_ALWAYS,
> +	  .size_idx = SE_CMD_ADDR_NO_SIZE },			/* container_hdr_addr */
> +};

[Severity: High]
Can the lack of size validation here allow the firmware to read past the bounds
of the allocated DMA buffer? 

If a user submits a command with an address pointing to the very end of the
shared memory window, the firmware might read unmapped or unowned memory,
potentially causing an IOMMU fault.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260831-imx-se-if-v43-0-a3deadbda4ef@nxp.com?part=5

  reply	other threads:[~2026-08-31  7:05 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-31 12:18 [PATCH v43 0/7] firmware: imx: driver for NXP secure-enclave pankaj.gupta
2026-08-31 12:18 ` [PATCH v43 1/7] Documentation/firmware: add imx/se to other_interfaces pankaj.gupta
2026-08-31 12:18 ` [PATCH v43 2/7] dt-bindings: arm: fsl: add imx-se-fw binding doc pankaj.gupta
2026-08-31  7:00   ` sashiko-bot
2026-08-31 12:18 ` [PATCH v43 3/7] firmware: imx: add driver for NXP EdgeLock Enclave pankaj.gupta
2026-08-31  7:05   ` sashiko-bot
2026-08-31 12:18 ` [PATCH v43 4/7] firmware: imx: device context dedicated to priv pankaj.gupta
2026-08-31 12:18 ` [PATCH v43 5/7] firmware: imx: adds miscdev pankaj.gupta
2026-08-31  7:05   ` sashiko-bot [this message]
2026-09-01 15:52     ` Pankaj Gupta (OSS)
2026-09-01 16:07       ` Frank Li
2026-08-31 12:18 ` [PATCH v43 6/7] arm64: dts: imx8ulp: add secure enclave node pankaj.gupta
2026-08-31  6:58   ` sashiko-bot
2026-08-31 12:18 ` [PATCH v43 7/7] arm64: dts: imx8ulp: add reserved memory for EdgeLock Enclave pankaj.gupta

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=20260831070508.252E01F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=Frank.Li@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=imx@lists.linux.dev \
    --cc=pankaj.gupta@oss.nxp.com \
    --cc=robh@kernel.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