Skip to contentSkip to conversation

dmaengine: ppc4xx: use assigned variable for dma_free_coherent()

PATCH In review Rosen Penev 3 participants 4 messages Sep 11 dmaengine

lore
Share & tools
lore
#0 lore raw

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.

Fixes 12458ea06efd7b44281e68fe59c950ec7d59c649 ("ppc440spe-adma: adds updated ppc440spe adma driver")
---
 drivers/dma/ppc4xx/adma.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/dma/ppc4xx/adma.c +1 -1
index 279a431ccae3..d0863394c723 100644
@@ -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
#1 lore raw
Thank 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
index 279a431ccae38..d0863394c7235 100644
@@ -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 -0
 	if (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
#2 lore raw
In reply to Rosen Penev
Quoted 6 lines · Rosen Penev

In some goto paths, adev->dev is unassigned. Use &ofdev->dev to cover those cases.

Fixes 12458ea06efd7b44281e68fe59c950ec7d59c649 ("ppc440spe-adma: adds updated ppc440spe adma driver")

---

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
index 279a431ccae3..d0863394c723 100644
@@ -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

#3 lore raw
Quoted 9 lines · Frank Li
Quoted 6 lines · Rosen Penev

In some goto paths, adev->dev is unassigned. Use &ofdev->dev to cover those cases.

Fixes 12458ea06efd7b44281e68fe59c950ec7d59c649 ("ppc440spe-adma: adds updated ppc440spe adma driver")

---

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
index 279a431ccae3..d0863394c723 100644
@@ -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