RE: [PATCH v38 5/7] firmware: imx: adds miscdev

"Pankaj Gupta (OSS)" <[email protected]>
Newsgroups dev.linux.lists.sashiko-reviews,dev.linux.lists.imx,org.kernel.vger.linux-devicetree
Message-ID <GV2PR04MB12271AB9B73BAAAB74524582295A42@GV2PR04MB12271.eurprd04.prod.outlook.com>
> > @@ -617,6 +617,6 @@
> >  void ele_set_sz_in_field_addr(u8 cmd, u32 size)  {
> >     switch (cmd) {
> >     case ELE_STORAGE_MASTER_EXPORT_REQ:
> >             ele_storage_master_export_addr_fields[0].buf_size = size;
> >             break;
>
> [Severity: High]
> If there are multiple secure enclave interfaces, do they share this global static
> array ele_storage_master_export_addr_fields? If two instances execute an
> export concurrently, could they race to overwrite this buf_size?
> If one instance's validation uses the other's size, might this allow a smaller
> bounds check to pass while the firmware executes a larger DMA write, resulting
> in out-of-bounds memory corruption?

Accepted. It will be fixed in v39

>
> > diff --git a/drivers/firmware/imx/ele_fw_api.c
> > b/drivers/firmware/imx/ele_fw_api.c
> > --- a/drivers/firmware/imx/ele_fw_api.c
> > +++ b/drivers/firmware/imx/ele_fw_api.c
> > @@ -152,7 +152,7 @@
> >     case ELE_STORAGE_OPEN_REQ:
> >             /* Might be cleared as part of tear down. */
> >             if (dev_ctx->strg_hdl) {
> >                     ret = -EEXIST;
> >                     break;
> >             }
> >             /*
> >              * Reject the storage-open request when another context is ...
> >              */
> >             scoped_guard(mutex, &priv->modify_lock)
> >                     if (priv->cmd_receiver_clbk_hdl.dev_ctx &&
> >                         priv->cmd_receiver_clbk_hdl.dev_ctx != dev_ctx)
> >                             ret = -EBUSY;
> >             if (rx_msg_sz < ELE_STORAGE_OPEN_RSP_SZ)
> >                     ret = -EINVAL;
> >             break;
> >
> > [ ... ]
> >
> > @@ -252,7 +252,7 @@
> >     case ELE_STORAGE_OPEN_REQ: {
> >             int rc;
> >
> >             /*
> > ...
> >              */
> >             dev_ctx->strg_hdl = rx_msg->data[1];
> >
> >             rc = set_dev_ctx_as_command_receiver(dev_ctx, false);
> >             if (rc)
> >                     dev_err(priv->dev,
> >                             "Failed to register %s as CMD-Receiver: %d\n",
> >                             dev_ctx->devname, rc);
> >             break;
> >     }
>
> [Severity: High]
> Since modify_lock is dropped before sending the command to firmware in the
> pre-check, could two processes concurrently pass this check and both receive
> storage handles from the firmware? If the second process fails registration in
> set_dev_ctx_as_command_receiver() but the error is just logged and discarded,
> wouldn't it successfully return the handle to userspace? Could this result in the
> firmware incorrectly routing the second process's NVM callbacks to the first
> registered process?

Not an issue.
Userspace call the IOCTL SE_IOCTL_ENABLE_CMD_RCV_STATUS,
to know the execution status of function set_dev_ctx_as_command_receiver().
If it fails, it will initiate ELE_STORAGE_CLOSE_REQ, immediately.

>
> > diff --git a/drivers/firmware/imx/ele_common.c
> > b/drivers/firmware/imx/ele_common.c
> > --- a/drivers/firmware/imx/ele_common.c
> > +++ b/drivers/firmware/imx/ele_common.c
> > @@ -140,4 +140,4 @@
> >             if (f->size_idx != SE_CMD_ADDR_NO_SIZE) { ...
> >             } else if (f->buf_size) {
> >                     /* buf_size: literal byte count
> >                      *           (FW-defined constant or saved at runtime).
> >                      */
> >                     if ((u64)f->buf_size > end - addr)
> >                             return -EACCES;
> >             }
>
> [Severity: High]
> If a malicious command receiver skips calling read() and directly issues a
> write() to send an export response, does buf_size remain at its default value of
> zero? If buf_size is zero, the check else if (f->buf_size) evaluates to false,
> completely bypassing the end-bounds check. Could an attacker exploit this by
> specifying an address at the very end of the shared memory window, causing the
> firmware to DMA the large export payload out of bounds?

Accepted. Add a check for last received command id verification se_cmd_receiver_allowed_rsp per "priv".
Will fix in v39.
>
> > [ ... ]
> >
> > @@ -367,4 +367,4 @@
> >             if (ret == 0) {
> > ...
> >                     spin_lock_irqsave(&se_clbk_hdl->clbk_rx_lock, flags);
> >                     se_clbk_hdl->rx_msg = NULL;
> >                     if (!completion_done(&se_clbk_hdl->done))
> >                             se_mark_fw_busy(dev_ctx);
> >
> >                     spin_unlock_irqrestore(&se_clbk_hdl->clbk_rx_lock,
> flags);
>
> [Severity: High]
> Is completion_done() the correct check to use in this timeout path? If device
> teardown runs concurrently and invokes complete_all(), won't
> completion_done() return true? This would cause the code to skip calling
> se_mark_fw_busy() and proceed to free the shared DMA buffer while the
> firmware might still be processing the command, potentially leading to a DMA-
> after-free memory corruption. Should this check use !se_clbk_hdl->rx_delivered
> instead, similar to the other paths?
>
Accepted. Will fix in v39.

> > 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
> > @@ -1885,5 +1885,5 @@
> >  static int se_if_fops_open(struct inode *nd, struct file *fp)  {
> >     struct miscdevice *miscdev = fp->private_data;
> >     struct se_if_open_gate *gate;
> > ...
> >     gate = container_of(miscdev, struct se_if_open_gate, miscdev);
> >
> >     if (!se_if_open_gate_get(gate))
> >             return -ENODEV;
>
> [Severity: High]
> Could the gate pointer be freed concurrently before se_if_open_gate_get() is
> called? When userspace calls open(), the VFS resolves the miscdev and drops
> misc_mtx. If device unbind executes at this exact moment,
> misc_deregister() can complete and the teardown path will free the gate
> structure. When the open thread resumes, won't it dereference a freed gate
> structure here, resulting in a use-after-free?

Not an issue.
Dereference gate before se_if_open_gate_get(): this is safe because
misc_open() in drivers/char/misc.c holds misc_mtx for the entire
duration of calling our .open callback, and misc_deregister() also
takes misc_mtx. Therefore teardown cannot call misc_deregister() - and
subsequently drop the device-owned kref that would free gate - while
we are executing here. Once se_if_open_gate_get() succeeds we own a
kref ourselves, so gate is safe to use after misc_mtx is released.

>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260820-imx-se-if-v38-0-
> [email protected]?part=5

NXP Confidential
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.