From: sashiko-bot@kernel.org
To: pankaj.gupta@oss.nxp.com
Cc: conor+dt@kernel.org, robh@kernel.org, devicetree@vger.kernel.org,
Frank.Li@kernel.org, imx@lists.linux.dev
Subject: Re: [PATCH v27 5/7] firmware: drivers: imx: adds miscdev
Date: Wed, 15 Jul 2026 17:36:48 +0000 [thread overview]
Message-ID: <20260715173648.D6C7C1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260715-imx-se-if-v27-5-bb7c45952f06@nxp.com>
Thank you for your contribution! Sashiko AI review found 13 potential issue(s) to consider:
- [High] The `read()` path drops `fops_lock` and `clbk_rx_lock` before accessing shared lists and `rx_msg`, leading to Use-After-Free and list corruption.
- [High] KASAN slab-out-of-bounds read in `se_val_rsp_hdr_n_status` due to insufficient response buffer size validation.
- [High] Indefinite hang during module unload or device unbind when userspace is blocked in `SE_IOCTL_CMD_SEND_RCV_RSP`.
- [High] Hung task panic triggered by signal interruption during long firmware waits in `ele_msg_rcv()`.
- [High] The `SE_IOCTL_CMD_SEND_RCV_RSP` ioctl silently swallows kernel-level validation errors, returning success to userspace.
- [High] Memory leak of dynamically allocated `se_buf_desc` structures when a device fd is closed without cleaning up pending buffers.
- [High] IOCTL error path zeroes out shared DMA memory buffers while the firmware might still be actively accessing them due to a timeout.
- [High] Fatal kernel crash during probe failure due to `dma_free_coherent` on an uninitialized pointer for the internal device context.
- [High] Unsynchronized clearing of `rx_msg_sz` in `se_if_fops_read()` causes lost commands and `-ENODEV` when interrupted by a signal.
- [High] TOCTOU race during device context creation in `open()` against unbind cleanup allows file operations on an unbound driver.
- [High] Race window during driver unbind between `cancel_work_sync()` and `se_clear_fw_busy()` allows work scheduling on freed memory.
- [Medium] Race condition exposing device node before probe initialization completes.
- [Medium] Mixing `goto`-based error handling with scope-based cleanup (`__free` and `guard`) violates kernel cleanup rules.
--
--- Patch [5]: [PATCH v27 5/7] firmware: drivers: imx: adds miscdev ---
commit 688f25f20d4d627be6c43a2c0f20ff6e2aa34b78
Author: Pankaj Gupta <pankaj.gupta@nxp.com>
firmware: drivers: imx: adds miscdev
Adds the driver for communication interface to secure-enclave, that
enables exchanging messages with NXP secure enclave HW IP(s)
like EdgeLock Enclave, from User-Space Applications via character driver.
Link: https://lkml.kernel.org/r/20260629-imx-se-if-v26-0-146446285744@nxp.com?part=5
> diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
> index 955b7409ff9fc..7deff38c46132 100644
> --- a/drivers/firmware/imx/ele_common.c
> +++ b/drivers/firmware/imx/ele_common.c
> @@ -67,6 +122,9 @@ int ele_msg_rcv(struct se_if_device_ctx *dev_ctx, struct se_clbk_handle *se_clbk
> * synchronized state.
> */
> if (READ_ONCE(priv->waiting_rsp_clbk_hdl.dev_ctx)) {
> + if (!is_rsp_wait_with_timeout)
> + return ret;
> +
> WRITE_ONCE(se_clbk_hdl->signal_rcvd, true);
> wait_uninterruptible = true;
> continue;
[Severity: High]
Can this sequence trigger a hung task panic on systems with the hung task
watchdog enabled?
In ele_msg_rcv(), if a signal interrupts the wait, the code sets
wait_uninterruptible = true and continues waiting. Since the timeout for
a standard command response is set to 5000 seconds, wouldn't waiting in
TASK_UNINTERRUPTIBLE for this long reliably crash the system?
> diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
> index 25f9cd5441f90..fb82df5c58d56 100644
> --- a/drivers/firmware/imx/se_ctrl.c
> +++ b/drivers/firmware/imx/se_ctrl.c
> @@ -197,11 +204,234 @@ static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se
> return 0;
> }
>
> +static void cleanup_se_shared_mem(struct se_if_device_ctx *dev_ctx)
> +{
> + struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
> + struct se_if_priv *priv = dev_ctx->priv;
> +
> + /* Free non-secure shared buffer. */
> + dma_free_coherent(priv->dev, MAX_DATA_SIZE_PER_USER,
> + se_shared_mem_mgmt->non_secure_mem.ptr,
> + se_shared_mem_mgmt->non_secure_mem.dma_addr);
[Severity: High]
Could this leak memory by failing to free the se_buf_desc items in the
pending_in and pending_out lists when the device file descriptor is closed?
[Severity: High]
Can this cause a kernel crash during probe failure?
If an internal command times out during probe, the internal context
priv_dev_ctx might be marked fw_busy before shared memory is allocated
(ptr is NULL).
Calling dma_free_coherent() with a NULL pointer and a size of 65536 bytes
could trigger a bug in the DMA subsystem.
> +static void se_dev_ctx_shared_mem_cleanup(struct se_if_device_ctx *dev_ctx)
> +{
> + struct se_shared_mem_mgmt_info *se_shared_mem_mgmt = &dev_ctx->se_shared_mem_mgmt;
> + struct list_head *pending_lists[] = {&se_shared_mem_mgmt->pending_in,
> + &se_shared_mem_mgmt->pending_out};
> + struct se_buf_desc *b_desc, *temp;
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(pending_lists); i++) {
> + list_for_each_entry_safe(b_desc, temp, pending_lists[i], link) {
> + if (b_desc->shared_buf_ptr)
> + memset(b_desc->shared_buf_ptr, 0, b_desc->size);
[Severity: High]
Does this zero out the shared DMA memory buffers while the firmware might
still be actively accessing them?
If ele_msg_send_rcv() times out, this cleanup is called on the error path.
Modifying active DMA buffers or reusing them for the next command could
corrupt firmware execution.
> +static void cleanup_dev_ctx(struct se_if_device_ctx *dev_ctx, bool is_fclose)
> +{
> + scoped_guard(mutex, &dev_ctx->fops_lock) {
> + if (dev_ctx->cleanup_done)
> + goto exit;
[Severity: High]
Can this cause an indefinite hang during unbind?
If userspace is blocked in ele_msg_rcv() waiting for a firmware response,
it holds fops_lock via scoped_cond_guard in se_ioctl(). This cleanup path
uninterruptibly blocks trying to acquire the same fops_lock, deadlocking
the unbind thread until the firmware replies or the timeout expires.
[Severity: Medium]
Does this violate the kernel cleanup subsystem rules?
Using a goto to jump completely out of a scoped_guard() block creates
confusing ownership semantics and can lead to bugs. The same issue appears
in ele_get_info() with __free(kfree).
> +static int se_ioctl_cmd_snd_rcv_rsp_handler(struct se_if_device_ctx *dev_ctx,
> + void __user *uarg)
> +{
[ ... ]
> + if (cmd_snd_rcv_rsp_info.rx_buf_sz < sizeof(struct se_msg_hdr) ||
> + cmd_snd_rcv_rsp_info.rx_buf_sz > MAX_ALLOWED_RX_MSG_SZ) {
> + se_ioctl_cmd_snd_rcv_cleanup(dev_ctx, uarg, &cmd_snd_rcv_rsp_info);
> + return -EINVAL;
> + }
[Severity: High]
Does this validation allow a user to allocate an rx_msg buffer of exactly
4 bytes?
In se_val_rsp_hdr_n_status(), msg->data[0] (bytes 4-7) is unconditionally
read. If the command bypasses size-mismatch validation (like
ELE_DEBUG_DUMP_REQ), this could cause a KASAN out-of-bounds read.
> + rsp_status_err =
> + se_val_rsp_hdr_n_status(priv, rx_msg, tx_msg->header.command,
> + cmd_snd_rcv_rsp_info.rx_buf_sz,
> + tx_msg->header.ver == priv->if_defs->base_api_ver);
> +
> + if (!rsp_status_err) {
> + err = se_dev_ctx_cpy_out_data(dev_ctx);
> + if (err < 0) {
> + se_ioctl_cmd_snd_rcv_cleanup(dev_ctx, uarg, &cmd_snd_rcv_rsp_info);
> + return err;
> + }
> + }
[Severity: High]
Is there a missing assignment to err here?
If se_val_rsp_hdr_n_status() fails, rsp_status_err is populated but never
assigned to err. The function falls through and returns the positive success
byte count from ele_msg_send_rcv(), silently swallowing the validation error
and misleading userspace.
> +static ssize_t se_if_fops_read(struct file *fp, char __user *buf, size_t size,
> + loff_t *ppos)
> +{
[ ... ]
> + /* We may need to copy the output data to user before
> + * delivering the completion message.
> + */
> + err = se_dev_ctx_cpy_out_data(dev_ctx);
> + if (err < 0)
> + goto exit;
[Severity: High]
Can this result in a use-after-free and list corruption?
The fops_lock is dropped before the blocking wait in ele_msg_rcv(). When
resuming, this code unconditionally accesses the pending_in and pending_out
lists in se_dev_ctx_cpy_out_data() without reacquiring fops_lock. If the
device was closed concurrently, the DMA memory and rx_msg could already be
freed.
> +exit:
> + priv->cmd_receiver_clbk_hdl.rx_msg_sz = 0;
> + se_dev_ctx_shared_mem_cleanup(dev_ctx);
> +
> + return err;
> +}
[Severity: High]
Does clearing rx_msg_sz locklessly here cause lost firmware commands?
If the wait in ele_msg_rcv() is interrupted by a signal, this jumps to exit
and clears the size. If a mailbox interrupt concurrently receives a message
and sets the size, this will overwrite it with 0. When userspace restarts
the read(), it will reject the valid message because rx_msg_sz is 0.
> +static int se_if_fops_open(struct inode *nd, struct file *fp)
> +{
[ ... ]
> + if (misc_dev_ctx->cleanup_done) {
> + err = -ENODEV;
> + goto out_unlock_misc;
> + }
> +
> + priv->dev_ctx_mono_count++;
> + err = init_device_context(priv, priv->dev_ctx_mono_count, &dev_ctx);
[Severity: High]
Is there a TOCTOU race here against unbind cleanup?
The fops_lock is dropped right after checking cleanup_done, but before
init_device_context() adds the new context to dev_ctx_list under modify_lock.
If se_if_probe_cleanup() runs in between, it could unbind the driver,
resulting in open() returning a file descriptor for a fully unbound device.
> +static void se_if_probe_cleanup(void *plat_dev)
> +{
[ ... ]
> + cancel_work_sync(&priv->fw_busy_work);
> + /*
> + * 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.
> + */
> + se_clear_fw_busy(priv);
[Severity: High]
Could this race with a late mailbox interrupt to cause a use-after-free?
cancel_work_sync() is called before se_clear_fw_busy() clears the fw_busy
state flag. If a mailbox interrupt arrives between these two calls, it will
see fw_busy is still set and call schedule_work() on the soon-to-be-freed
priv->fw_busy_work structure.
> @@ -312,15 +1449,22 @@ static int se_if_probe(struct platform_device *pdev)
> return dev_err_probe(dev, ret,
> "Failed to init reserved memory region.");
> }
>
> - 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.",
[Severity: Medium]
Could this expose the device node to userspace before probe initialization
completes?
misc_register() is called inside init_misc_device_context(), but
se_if_probe() continues to initialize load_fw and SoC info after this returns.
If userspace immediately opens the device and sends a command, it could bypass
the se_load_firmware() step.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260715-imx-se-if-v27-0-bb7c45952f06@nxp.com?part=5
next prev parent reply other threads:[~2026-07-15 17:36 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-15 18:09 [PATCH v27 0/7] firmware: imx: driver for NXP secure-enclave pankaj.gupta
2026-07-15 18:09 ` [PATCH v27 1/7] Documentation/firmware: add imx/se to other_interfaces pankaj.gupta
2026-07-15 17:25 ` sashiko-bot
2026-07-15 18:09 ` [PATCH v27 2/7] dt-bindings: arm: fsl: add imx-se-fw binding doc pankaj.gupta
2026-07-15 17:27 ` sashiko-bot
2026-07-15 18:09 ` [PATCH v27 3/7] firmware: imx: add driver for NXP EdgeLock Enclave pankaj.gupta
2026-07-15 17:36 ` sashiko-bot
2026-07-15 22:19 ` Uwe Kleine-König
2026-07-15 18:09 ` [PATCH v27 4/7] firmware: imx: device context dedicated to priv pankaj.gupta
2026-07-15 17:34 ` sashiko-bot
2026-07-15 18:09 ` [PATCH v27 5/7] firmware: drivers: imx: adds miscdev pankaj.gupta
2026-07-15 17:36 ` sashiko-bot [this message]
2026-07-15 18:09 ` [PATCH v27 6/7] arm64: dts: imx8ulp: add secure enclave node pankaj.gupta
2026-07-15 17:31 ` sashiko-bot
2026-07-15 18:09 ` [PATCH v27 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=20260715173648.D6C7C1F000E9@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.