[v3,1/4] dmaengine: vchan: add vchan_chan_name() to get channel device name
Commit Message
From: Frank Li <Frank.Li@nxp.com>
Introduce vchan_chan_name() to obtain the DMA channel device name.
Use a dedicated helper instead of directly accessing dma_chan::dev
so callers remain unaffected by an upcoming rename of the struct member.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
drivers/dma/arm-dma350.c | 2 +-
drivers/dma/loongson/loongson2-apb-cmc-dma.c | 2 +-
drivers/dma/stm32/stm32-dma.c | 2 +-
drivers/dma/stm32/stm32-dma3.c | 4 ++--
drivers/dma/virt-dma.h | 11 +++++++++++
5 files changed, 16 insertions(+), 5 deletions(-)
Comments
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Inverted devres teardown order in stm32_dma_probe error path causes a Use-After-Free of the DMA channel name.
--
commit 7119ae3e70ddf3efdd1474a7d8b5fbb1ec66bf04
Author: Frank Li <Frank.Li@nxp.com>
dmaengine: vchan: add vchan_chan_name() to get channel device name
This commit introduces the vchan_chan_name() helper to obtain the DMA channel
device name. It updates various drivers to use this helper instead of directly
accessing dma_chan::dev, ensuring they remain unaffected by upcoming struct
member renames.
[ ... ]
> diff --git a/drivers/dma/stm32/stm32-dma.c b/drivers/dma/stm32/stm32-dma.c
> index d3ad78562a140..3e8151e2ad75a 100644
> --- a/drivers/dma/stm32/stm32-dma.c
> +++ b/drivers/dma/stm32/stm32-dma.c
> @@ -1668,7 +1668,7 @@ static int stm32_dma_probe(struct platform_device *pdev)
>
> ret = devm_request_irq(&pdev->dev, chan->irq,
> stm32_dma_chan_irq, 0,
> - dev_name(chan2dev(chan)), chan);
> + vchan_chan_name(&chan->vchan), chan);
[Severity: High]
This isn't a bug introduced by this patch, but is it possible this exposes a
pre-existing use-after-free of the DMA channel name in the probe error path?
The dynamically allocated name from vchan_chan_name() is passed to
devm_request_irq(), binding the IRQ action's name pointer to the string.
If stm32_dma_probe() fails later (for example, if of_dma_controller_register()
fails), it jumps to the error label:
err_unregister:
dma_async_device_unregister(dd);
clk_free:
clk_disable_unprepare(dmadev->clk);
Calling dma_async_device_unregister() here manually frees the DMA channels
and their associated kobject names. However, because the IRQs were requested
using devm_request_irq(), they remain active and are not freed until later
when the probe function returns and devres unwinds.
Could this inverted teardown sequence create a window where the IRQ subsystem
holds a dangling pointer to the freed name string, potentially leading to
memory corruption or a kernel oops if /proc/interrupts is read?
[ ... ]
@@ -512,7 +512,7 @@ static int d350_alloc_chan_resources(struct dma_chan *chan)
{
struct d350_chan *dch = to_d350_chan(chan);
int ret = request_irq(dch->irq, d350_irq, IRQF_SHARED,
- dev_name(&dch->vc.chan.dev->device), dch);
+ vchan_chan_name(&dch->vc), dch);
if (!ret)
writel_relaxed(CH_INTREN_DONE | CH_INTREN_ERR, dch->base + CH_INTREN);
@@ -678,7 +678,7 @@ static int loongson2_cmc_dma_probe(struct platform_device *pdev)
return lchan->irq;
ret = devm_request_irq(dev, lchan->irq, loongson2_cmc_dma_chan_irq, IRQF_SHARED,
- dev_name(chan2dev(lchan)), lchan);
+ vchan_chan_name(&lchan->vchan), lchan);
if (ret)
return ret;
}
@@ -1668,7 +1668,7 @@ static int stm32_dma_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, chan->irq,
stm32_dma_chan_irq, 0,
- dev_name(chan2dev(chan)), chan);
+ vchan_chan_name(&chan->vchan), chan);
if (ret) {
dev_err(&pdev->dev,
"request_irq failed with err %d channel %d\n",
@@ -1892,10 +1892,10 @@ static int stm32_dma3_probe(struct platform_device *pdev)
chan->irq = ret;
ret = devm_request_irq(&pdev->dev, chan->irq, stm32_dma3_chan_irq, 0,
- dev_name(chan2dev(chan)), chan);
+ vchan_chan_name(&chan->vchan), chan);
if (ret) {
dev_err_probe(&pdev->dev, ret, "Failed to request channel %s IRQ\n",
- dev_name(chan2dev(chan)));
+ vchan_chan_name(&chan->vchan));
goto err_clk_disable;
}
}
@@ -209,6 +209,17 @@ static inline void vchan_free_chan_resources(struct virt_dma_chan *vc)
vchan_dma_desc_free_list(vc, &head);
}
+/**
+ * vchan_chan_name - Return vchan DMA channel device name
+ * @vc: virtual channel
+ *
+ * Return: The name of the DMA channel device
+ */
+static inline const char *vchan_chan_name(struct virt_dma_chan *vc)
+{
+ return dma_chan_name(&vc->chan);
+}
+
/**
* vchan_synchronize() - synchronize callback execution to the current context
* @vc: virtual channel to synchronize