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
next prev parent 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