RE: [PATCH v31 4/7] firmware: imx: device context dedicated to priv
"Pankaj Gupta (OSS)" <[email protected]> Wed, 29 Jul 2026 17:48:39 +0000
| Newsgroups | dev.linux.lists.imx,dev.linux.lists.sashiko-reviews,org.kernel.vger.linux-devicetree |
|---|---|
| Message-ID | <GV2PR04MB1227106F264A34960FC56CDBF95CA2@GV2PR04MB12271.eurprd04.prod.outlook.com> |
> - [High] se_if_probe_cleanup() frees priv->priv_dev_ctx before freeing the
> mailbox channels, creating a race condition where the mailbox RX callback can
> access a freed devname string on the error logging path.
Confirmed. Freeing priv_dev_ctx (hence priv_dev_ctx->devname) while the rx
channel is still live leaves the sz_mismatch dev_err() in se_if_rx_callback()
free to dereference a dangling devname. Fix is a reorder in
se_if_probe_cleanup() (see the last hunk).
> > @@ -294,13 +301,14 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
> > se_clbk_hdl->rx_msg_sz = min_t(u32, rx_msg_sz, MAX_NVM_MSG_LEN);
> > + devname = se_clbk_hdl->dev_ctx->devname;
> > memcpy(se_clbk_hdl->rx_msg, msg, se_clbk_hdl->rx_msg_sz);
> > complete(&se_clbk_hdl->done);
> > spin_unlock_irqrestore(&se_clbk_hdl->clbk_rx_lock, flags);
> > if (sz_mismatch)
> > dev_err(dev,
> > - "CMD-RCVER NVM: hdr(0x%x) ...",
> > + "%s: CMD-RCVER NVM: hdr(0x%x) ...",
> > + devname, *(u32 *)header,
The cache-then-log pattern here is intentional: devname is read under
clbk_rx_lock, and the dev_err() is deliberately emitted after dropping the
spinlock so we do not log under the lock. The pattern is safe as long as the
priv_dev_ctx that devname points into is not freed while a callback may still
run. That guarantee is missing in this commit's teardown, not in this hunk. No
change here.
> > @@ -335,14 +343,15 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
> > + devname = se_clbk_hdl->dev_ctx->devname;
> > memcpy(se_clbk_hdl->rx_msg, msg, se_clbk_hdl->rx_msg_sz);
> > complete(&se_clbk_hdl->done);
> > spin_unlock_irqrestore(&se_clbk_hdl->clbk_rx_lock, flags);
> > if (sz_mismatch)
> > dev_err(dev,
> > - "Rsp to CMD: hdr(0x%x) ...",
> > + "%s: Rsp to CMD: hdr(0x%x) ...",
> > + devname, *(u32 *)header,
Same disposition. On the rsp_tag path devname is
priv->waiting_rsp_clbk_hdl.dev_ctx->devname, which for a probe transaction is
priv->priv_dev_ctx->devname - exactly the object teardown frees too early. Note
complete() here wakes the probe waiter, which can drive devres unwind and enter
se_if_probe_cleanup() while this callback is still preempted between the
spin_unlock and the dev_err(). Lifetime must be enforced in the cleanup path. No
change here.
> > @@ -309,6 +339,11 @@ static void se_if_probe_cleanup(void *plat_dev)
> > if (!priv)
> > return;
> > + if (priv->priv_dev_ctx) {
> > + kfree(priv->priv_dev_ctx->devname);
> > + kfree(priv->priv_dev_ctx);
> > + }
> > +
> > if (priv->rx_chan)
> > mbox_free_channel(priv->rx_chan);
> > if (priv->tx_chan)
> > mbox_free_channel(priv->tx_chan);
This is the defect. priv_dev_ctx (and devname) are freed while priv->rx_chan is
still registered, so a se_if_rx_callback() that has already cached devname and
is about to call dev_err() can dereference freed memory.
Fix: move the priv_dev_ctx/devname free below mbox_free_channel(). Freeing the
rx channel first quiesces the rx path (no new callbacks, and any in-flight one
has completed), so devname is no longer reachable by the callback when it is
freed. Placing it just before kfree(priv) at the end of the function:
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
@@ -339,11 +339,6 @@ static void se_if_probe_cleanup(void *plat_dev)
if (!priv)
return;
- if (priv->priv_dev_ctx) {
- kfree(priv->priv_dev_ctx->devname);
- kfree(priv->priv_dev_ctx);
- }
-
if (priv->rx_chan)
mbox_free_channel(priv->rx_chan);
if (priv->tx_chan)
@@ -363,6 +358,11 @@ static void se_if_probe_cleanup(void *plat_dev)
dev_set_drvdata(dev, NULL);
+ if (priv->priv_dev_ctx) {
+ kfree(priv->priv_dev_ctx->devname);
+ kfree(priv->priv_dev_ctx);
+ }
+
kfree(priv);
}
This gives the required ordering:
mbox_free_channel(rx) -> kfree(priv_dev_ctx->devname) -> kfree(priv)
Because the rx channel is torn down before devname is freed, a
se_if_rx_callback() can neither start nor still be running when devname goes
away, closing the window you describe.
> Would it be safer to free priv_dev_ctx after the mailbox channels are freed?
Yes. The reorder above does exactly that. Will fold it into the next respin of this patch.
Next re-spin depends of this patch depends if there are any more comments in 5/7, require code changes.
If not then there will be no respin plan, as this change is replaced and cleaned in 5/7.
--