All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: pankaj.gupta@oss.nxp.com
Cc: imx@lists.linux.dev, Frank.Li@kernel.org, conor+dt@kernel.org,
	devicetree@vger.kernel.org, robh@kernel.org
Subject: Re: [PATCH v29 5/7] firmware: drivers: imx: adds miscdev
Date: Tue, 21 Jul 2026 10:54:48 +0000	[thread overview]
Message-ID: <20260721105449.200D91F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260721-imx-se-if-v29-5-04a362f4fcca@nxp.com>

Thank you for your contribution! Sashiko AI review found 10 potential issue(s) to consider:
- [Critical] Arbitrary physical memory read/write vulnerability (Confused Deputy) via SE_IOCTL_CMD_SEND_RCV_RSP.
- [High] Use-After-Free of `gate` and `miscdev` due to race between unbind and VFS `open`.
- [High] Unbind deadlock/hang for up to 5000 seconds due to incorrect ordering of `complete_all` and `fops_lock` acquisition.
- [High] Overwriting a successful firmware transaction with `-ERESTARTSYS` leads to double execution with zeroed DMA buffers.
- [High] NULL pointer dereference in `se_if_rx_callback` due to clearing `drvdata` while the mailbox channel is active.
- [High] Out-of-bounds read in `se_if_rx_callback` by trusting unvalidated firmware payload length.
- [High] Premature freeing of `gen_pool` DMA buffer on timeout risks silent memory corruption.
- [Medium] Lockdep false positive 'possible recursive locking detected' on `fops_lock`.
- [Medium] Early device exposure to userspace before probe initialization is complete.
- [Low] Implicit compiler padding in UAPI structure `se_ioctl_cmd_snd_rcv_rsp_info`.
--

--- Patch [5]: [PATCH v29 5/7] firmware: drivers: imx: adds miscdev ---
commit a4962df1c1e6848f6dea7cc1ccb64c5abd9c4213
Author: Pankaj Gupta <pankaj.gupta@nxp.com>
Subject: firmware: drivers: imx: adds miscdev

This patch adds the driver for a communication interface to the NXP
secure-enclave. It exposes a character device to userspace for exchanging
messages with hardware IPs like EdgeLock Enclave. It also implements
command validation, shared memory management, and power/reset command
restrictions.

> diff --git a/include/uapi/linux/se_ioctl.h b/include/uapi/linux/se_ioctl.h
> new file mode 100644
> index 0000000000000..ea14cec05020d
> --- /dev/null
> +++ b/include/uapi/linux/se_ioctl.h
> @@ -0,0 +1,97 @@
[ ... ]
> +struct se_ioctl_cmd_snd_rcv_rsp_info {
> +	__u64 tx_buf;
> +	__u32 tx_buf_sz;
> +	__u64 rx_buf;
> +	__u32 rx_buf_sz;
> +};

[Severity: Low]
Will this struct have implicit compiler padding after the 32-bit fields,
potentially causing UAPI size differences across architectures?

> diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
> index 524ebc0f697e6..28b835f2880fb 100644
> --- a/drivers/firmware/imx/ele_base_msg.c
> +++ b/drivers/firmware/imx/ele_base_msg.c
> @@ -15,24 +15,65 @@
[ ... ]
> +static void ele_get_info_cleanup(struct se_if_priv *priv, u32 *buf, dma_addr_t d_addr,
> +				 size_t size)
> +{
[ ... ]
> +	if (priv->mem_pool)
> +		gen_pool_free(priv->mem_pool, (unsigned long)buf, size);
> +	else if (!se_is_fw_busy_ctx(priv->priv_dev_ctx))
> +		se_dev_ctx_shared_mem_cleanup(priv->priv_dev_ctx);
> +}

[Severity: High]
Could the gen_pool_free() path free memory while the hardware is still busy?
The standard allocation path uses a se_is_fw_busy_ctx() guard to prevent
freeing memory the hardware might still write to, but that guard is missing
here, risking silent memory corruption if a timeout occurred.

> diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
> index a350e83a274a1..fbb6e584341a1 100644
> --- a/drivers/firmware/imx/ele_common.c
> +++ b/drivers/firmware/imx/ele_common.c
> @@ -226,6 +281,7 @@ static bool check_hdr_exception_for_sz(struct se_if_priv *priv,
>  void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
>  {
>  	struct se_clbk_handle *se_clbk_hdl;
> +	bool schedule_fw_busy_work = false;
>  	struct device *dev = mbox_cl->dev;
>  	struct se_msg_hdr *header;
>  	bool sz_mismatch = false;
> @@ -305,9 +361,13 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
[ ... ]
>  	priv = dev_get_drvdata(dev);
>  
>  	/* The function can be called with NULL msg */
>  	if (IS_ERR_OR_NULL(msg)) {
[ ... ]
>  	header = msg;
>  	rx_msg_sz = header->size << 2;
>  
>  	/* Incoming command: wake up the receiver if any. */
>  	if (header->tag == priv->if_defs->cmd_tag) {

[Severity: High]
Can priv be NULL here if the callback fires during driver unbind?
In se_if_probe_cleanup(), dev_set_drvdata() clears the private data pointer
before devres frees the active mailbox channels. A late interrupt would
dereference the NULL pointer.

> [ ... ]
>  		se_clbk_hdl->rx_msg_sz = rx_msg_sz;
>  		memcpy(se_clbk_hdl->rx_msg, msg, se_clbk_hdl->rx_msg_sz);
>  		complete(&se_clbk_hdl->done);

[Severity: High]
Does this blindly trust the firmware-provided header->size for the copy?
If the mailbox driver's msg buffer is smaller than rx_msg_sz, this could
result in an out-of-bounds read that copies arbitrary kernel memory into
the response buffer returned to userspace.

> diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
> index cd4d27dd98ce1..3c14964830a6d 100644
> --- a/drivers/firmware/imx/se_ctrl.c
> +++ b/drivers/firmware/imx/se_ctrl.c
> @@ -243,11 +250,269 @@ static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se
[ ... ]
> +static int load_firmware(struct se_if_priv *priv, const u8 *se_img_file_to_load)
> +{
[ ... ]
> +	/*
> +	 * Serialize access to priv_dev_ctx shared memory to prevent pos
> +	 * corruption if two driver-internal callers run concurrently (e.g.
> +	 * ele_get_info() racing with load_firmware()).
> +	 */
> +	scoped_guard(mutex, &priv->priv_dev_ctx->fops_lock) {
> +		se_fw_buf_len = fw->size;

[Severity: Medium]
Could this trigger a lockdep warning for recursive locking? The ioctl path
already holds a fops_lock, and taking the internal context's lock of the
same class here is valid hierarchical locking but might be flagged as a
deadlock by static analysis.

> @@ -261,18 +526,909 @@ static int init_misc_device_context(struct se_if_priv *priv, int ch_id,
[ ... ]
> +static int se_ioctl_cmd_snd_rcv_rsp_handler(struct se_if_device_ctx *dev_ctx,
> +					    void __user *uarg)
> +{
[ ... ]
> +	err = ele_msg_send_rcv(dev_ctx, tx_msg, cmd_snd_rcv_rsp_info.tx_buf_sz,
> +			       rx_msg, cmd_snd_rcv_rsp_info.rx_buf_sz);
> +	if (err < 0) {
> +		se_ioctl_cmd_snd_rcv_cleanup(dev_ctx, uarg, &cmd_snd_rcv_rsp_info);
> +
> +		return err;
> +	}

[Severity: Critical]
Does this allow arbitrary physical memory read/write vulnerabilities? Since
the earlier se_chk_tx_msg_hdr() check only verifies the UAPI command header,
user-controlled payloads containing embedded physical DMA addresses are sent
directly to the hardware here without validation. An attacker could forge
addresses to overwrite kernel memory.

[Severity: High]
If ele_msg_send_rcv() successfully completed a transaction on the hardware
but was interrupted by a signal, it overwrites the success with -ERESTARTSYS.
Does returning that negative error here cause issues? This triggers the
se_ioctl_cmd_snd_rcv_cleanup() handler which zeros the shared DMA input
buffers. The VFS will then restart the ioctl and execute a second time with
all-zero input parameters.

> +static int se_if_fops_open(struct inode *nd, struct file *fp)
> +{
> +	struct miscdevice *miscdev = fp->private_data;
> +	struct se_if_open_gate *gate;
> +	struct se_if_device_ctx *misc_dev_ctx;
> +	struct se_if_device_ctx *dev_ctx;
> +	struct se_if_priv *priv;
> +	int err = 0;
> +
> +	gate = container_of(miscdev, struct se_if_open_gate, miscdev);
> +
> +	if (!se_if_open_gate_get(gate))
> +		return -ENODEV;

[Severity: High]
Is there a use-after-free race here against module removal?
During unbind, se_if_probe_cleanup() calls misc_deregister() and frees
the gate structure. This does not synchronize with concurrent open() calls
that have already resolved the device in the VFS, leading to a dereference
of the freed miscdev and gate when the delayed fops->open runs.

> @@ -310,6 +1467,67 @@ static void se_if_probe_cleanup(void *plat_dev)
[ ... ]
> +	while (true) {
> +		dev_ctx = NULL;
> +
> +		scoped_guard(mutex, &priv->modify_lock) {
> +			if (list_empty(&priv->dev_ctx_list))
> +				goto out_done;
> +
> +			dev_ctx = list_first_entry(&priv->dev_ctx_list,
> +						   struct se_if_device_ctx, link);
> +
> +			/* pin this context so close() cannot free it under us */
> +			kref_get(&dev_ctx->refcount);
> +			dlink_dev_ctx(dev_ctx);
> +		}
> +
> +		/*
> +		 * Local cleanup outside the global lock avoids ABBA deadlock
> +		 * with paths that already take dev_ctx->fops_lock first.
> +		 */
> +		cleanup_dev_ctx(dev_ctx, false);
> +		kref_put(&dev_ctx->refcount, se_if_dev_ctx_release);
> +	}
> +out_done:
> +
> +	/*
> +	 * A timed-out synchronous command may have retained a dev_ctx through
> +	 * priv->fw_busy_dev_ctx even after the fd was closed and the context was
> +	 * removed from dev_ctx_list. If no late response arrived, release that
> +	 * retained context during driver teardown.
> +	 *
> +	 * se_clear_fw_busy() is idempotent and internally checks
> +	 * priv->fw_busy_dev_ctx under fw_busy_lock.
> +	 */
> +	complete_all(&priv->waiting_rsp_clbk_hdl.done);

[Severity: High]
Will this cause a deadlock during driver unbind?
If an ioctl thread is blocked waiting for the done completion, it currently
holds dev_ctx->fops_lock. Calling cleanup_dev_ctx() here attempts to acquire
that same lock and blocks indefinitely, because the complete_all() intended
to wake the ioctl thread is placed after this loop.

> @@ -418,13 +1653,12 @@ static int se_if_probe(struct platform_device *pdev)
[ ... ]
> -	ret = init_misc_device_context(priv, 0, &priv->priv_dev_ctx);
> +	ret = init_misc_device_context(priv, 0, &priv->priv_dev_ctx, &se_if_fops);
>  	if (ret)
>  		return dev_err_probe(dev, ret,
>  				     "Failed[0x%x] to create device contexts.",
>  				     ret);
>  
> -	/* By default, there is no pending FW to be loaded.*/
>  	if (se_info->imem_state_mgmt) {
>  		load_fw = get_load_fw_instance(priv);
>  
[ ... ]
>  	if (if_node->if_defs.se_if_type == SE_TYPE_ID_HSM) {
>  		ret = get_se_soc_info(priv, se_info);

[Severity: Medium]
Could exposing the miscdevice to userspace this early lead to TOCTOU races?
The device is registered before get_se_soc_info() is queried or the IMEM
DMA buffer is allocated, allowing userspace to open the device and interact
with uninitialized state.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260721-imx-se-if-v29-0-04a362f4fcca@nxp.com?part=5

  reply	other threads:[~2026-07-21 10:54 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-21 11:23 [PATCH v29 0/7] firmware: imx: driver for NXP secure-enclave pankaj.gupta
2026-07-21 11:23 ` [PATCH v29 1/7] Documentation/firmware: add imx/se to other_interfaces pankaj.gupta
2026-07-21 10:37   ` sashiko-bot
2026-07-21 11:23 ` [PATCH v29 2/7] dt-bindings: arm: fsl: add imx-se-fw binding doc pankaj.gupta
2026-07-21 11:23 ` [PATCH v29 3/7] firmware: imx: add driver for NXP EdgeLock Enclave pankaj.gupta
2026-07-21 10:49   ` sashiko-bot
2026-07-21 10:50   ` Frieder Schrempf
2026-07-22 14:32     ` Frieder Schrempf
2026-07-21 11:23 ` [PATCH v29 4/7] firmware: imx: device context dedicated to priv pankaj.gupta
2026-07-21 10:51   ` sashiko-bot
2026-07-21 11:23 ` [PATCH v29 5/7] firmware: drivers: imx: adds miscdev pankaj.gupta
2026-07-21 10:54   ` sashiko-bot [this message]
2026-07-21 11:23 ` [PATCH v29 6/7] arm64: dts: imx8ulp: add secure enclave node pankaj.gupta
2026-07-21 10:57   ` sashiko-bot
2026-07-21 11:23 ` [PATCH v29 7/7] arm64: dts: imx8ulp-evk: add reserved memory property 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=20260721105449.200D91F000E9@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.