dmaengine: ppc4xx: use assigned variable for dma_free_coherent()
PATCH 1/1 dmaengine: ppc4xx: use assigned variable for dma_free_coherent()
In some goto paths, adev->dev is unassigned. Use &ofdev->dev to cover those cases.
--- drivers/dma/ppc4xx/adma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/dma/ppc4xx/adma.c +1 -1
@@ -4212,7 +4212,7 @@ static int ppc440spe_adma_probe(struct platform_device *ofdev)else iounmap (adev->dma_reg); err_regs_alloc: -dma_free_coherent (adev->dev, adev->pool_size, +dma_free_coherent (&ofdev->dev, adev->pool_size, adev->dma_desc_pool_virt, adev->dma_desc_pool); err_dma_alloc:
Signature · 1 line
2.55.0
[email protected]
AI reviewThank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing dma_mapping_error() checks can lead to memory corruption.
- [High] Missing tasklet_kill() in probe error path leads to Use-After-Free.
- [High] I/O memory leak due to shared refcount gating in iounmap.
- [High] Missing bounds check on cell-index device tree property causes out-of-bounds accesses.
- [High] Dangling err_irq left registered on probe error path leads to Use-After-Free.
- [High] Lockless concurrent access to global ppc440spe_adma_chan_list causes list corruption or UAF. --
commit d4a21e27d9b93a598c7085124df07419a304c246
Author: Rosen Penev <[email protected]>
dmaengine: ppc4xx: use assigned variable for dma_free_coherent()
This commit fixes a potential issue in the error handling path of ppc440spe_adma_probe() where adev->dev may be unassigned. It changes the dma_free_coherent() call to use &ofdev->dev instead.
drivers/dma/ppc4xx/adma.c static int ppc440spe_adma_probe(struct platform_device *ofdev) · line 4217
Quoted 12 lines
drivers/dma/ppc4xx/adma.c +1
-1@@ -4212,7 +4212,7 @@ static int ppc440spe_adma_probe(struct platform_device *ofdev)else iounmap (adev->dma_reg); err_regs_alloc: -dma_free_coherent (adev->dev, adev->pool_size, +dma_free_coherent (&ofdev->dev, adev->pool_size, adev->dma_desc_pool_virt, adev->dma_desc_pool);
[Severity: High]
This isn't a bug introduced by this patch, but while reviewing the probe function, I noticed the destination pages are mapped without validation:
Quoted 3 lines
drivers/dma/ppc4xx/adma.c +0
-0if (adev->id !=PPC440SPE_XOR_ID ) {chan->pdest_page = alloc_page(GFP_KERNEL); chan->qdest_page = alloc_page(GFP_KERNEL);
[ ... ]
Quoted 4 lines
chan->pdest = dma_map_page(&ofdev->dev, chan->pdest_page, 0, PAGE_SIZE, DMA_BIDIRECTIONAL); chan->qdest = dma_map_page(&ofdev->dev, chan->qdest_page, 0, PAGE_SIZE, DMA_BIDIRECTIONAL);
Can the lack of a dma_mapping_error() check here lead to memory corruption?
If the IOMMU or memory allocator is exhausted, dma_map_page() returns an error address which would then be written into DMA descriptors. I also noticed that ppc440spe_test_raid6() similarly maps a test page without validation.
[Severity: High]
This is a pre-existing issue, but is there a risk of a use-after-free in this error path?
Quoted 3 lines
err_dev_reg:ppc440spe_adma_release_irqs(adev, chan);
err_irq:
[ ... ]
Quoted 2 lines
err_page_alloc:kfree(chan);
The error path invokes IRQ cleanup but fails to call tasklet_kill(&chan->irq_tasklet) before freeing the channel memory.
If an interrupt fires and schedules the tasklet before kfree(chan) runs, would the tasklet dereference the freed memory to acquire the spinlock when ppc440spe_adma_tasklet() ultimately executes?
[Severity: High]
This isn't a bug introduced by this patch, but it looks like the I/O memory could be leaked:
Quoted 1 line
adev->i2o_reg = of_iomap(np, 0);
[ ... in ppc440spe_adma_release_irqs() ... ]
Quoted 4 lines
if (atomic_dec_and_test(&ppc440spe_adma_err_irq_ref)) {
irq_dispose_mapping(adev->err_irq);
iounmap(adev->i2o_reg);
}Are we permanently leaking the physical I/O space virtual mapping here?
Since adev->i2o_reg is mapped unconditionally on a per-device basis during setup, gating the unmap operation behind a shared IRQ reference counter means that if one engine unbinds or fails probe while the other is still active, the refcount remains > 0 and its unique mapping is skipped.
[Severity: High]
This is a pre-existing issue, but could missing bounds checking on the device tree property cause out-of-bounds accesses?
Quoted 1 line
idx = of_get_property(np, "cell-index", &len);
[ ... ]
Quoted 1 line
id = *idx;
[ ... ]
Quoted 1 line
adev->id = id;
The property is read directly into the identifier without validation.
If the ID is malformed, wouldn't this cause out-of-bounds array writes later in the fast paths, such as to the 3-element array chan_first_cdb[chan->device->id] in ppc440spe_adma_tx_submit() and chan_last_sub[chan->device->id] in ppc440spe_dma_put_desc()?
[Severity: High]
This isn't a bug introduced by this patch, but does the setup error path leave a dangling interrupt registered?
Quoted 4 lines
err_req2:free_irq(adev->irq, chan); err_req1: irq_dispose_mapping(adev->irq);
The error path in ppc440spe_adma_setup_irqs() fails to free adev->err_irq before returning.
Since kfree(chan) is called later in the probe error path, could the interrupt handler ppc440spe_adma_err_handler() access the freed chan pointer if the error interrupt fires?
[Severity: High]
This is a pre-existing issue, but might there be a race condition when accessing the global channel list?
Quoted 1 line
list_add_tail(&ref->node, &ppc440spe_adma_chan_list);
Is it safe to append to and delete from ppc440spe_adma_chan_list without any synchronization?
The list is modified globally in ppc440spe_adma_probe() and ppc440spe_adma_remove(), while being traversed by ppc440spe_async_tx_find_best_channel() without holding any spinlock or RCU read lock.
Could this lead to list corruption or a use-after-free if the exported symbol is called during a driver unbind?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Quoted 6 lines · Rosen Penev
In some goto paths,
adev->devis unassigned. Use&ofdev->devto cover those cases.Fixes 12458ea06efd7b44281e68fe59c950ec7d59c649 ("ppc440spe-adma: adds updated ppc440spe adma driver")Signed-off-by Rosen Penev <[email protected]>---
Please use dmam_alloc_coherent() to fix this problem.
Frank
Quoted 19 lines
drivers/dma/ppc4xx/adma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/dma/ppc4xx/adma.c +1
-2@@ -4212,7 +4212,7 @@ static int ppc440spe_adma_probe(struct platform_device *ofdev)else iounmap (adev->dma_reg); err_regs_alloc: -dma_free_coherent (adev->dev, adev->pool_size, +dma_free_coherent (&ofdev->dev, adev->pool_size, adev->dma_desc_pool_virt, adev->dma_desc_pool); err_dma_alloc: --2.55.0
Quoted 9 lines · Frank Li
Quoted 6 lines · Rosen Penev
In some goto paths,
adev->devis unassigned. Use&ofdev->devto cover those cases.Fixes 12458ea06efd7b44281e68fe59c950ec7d59c649 ("ppc440spe-adma: adds updated ppc440spe adma driver")Signed-off-by Rosen Penev <[email protected]>---
Please use
dmam_alloc_coherent()to fix this problem.
I did just that in a future patch. Might be worthwhile to have this first for potential backport purposes.
Quoted 22 lines
Frank
Quoted 19 lines
drivers/dma/ppc4xx/adma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/dma/ppc4xx/adma.c +1
-2@@ -4212,7 +4212,7 @@ static int ppc440spe_adma_probe(struct platform_device *ofdev)else iounmap (adev->dma_reg); err_regs_alloc: -dma_free_coherent (adev->dev, adev->pool_size, +dma_free_coherent (&ofdev->dev, adev->pool_size, adev->dma_desc_pool_virt, adev->dma_desc_pool); err_dma_alloc: --2.55.0