Re: [PATCH v3 02/11] dmaengine: switchtec-dma: fix resource leak in alloc_chan_resources

[email protected] Mon, 27 Jul 2026 18:40:23 +0000
Newsgroups org.kernel.vger.dmaengine,org.kernel.vger.linux-pci
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

New issues:
- [High] DMA use-after-free due to missing channel halt in the allocation error path.

Pre-existing issues:
- [High] Race condition in driver teardown leading to MMIO use-after-free and kernel oops.
--

--- Patch [2]: [PATCH v3 02/11] dmaengine: switchtec-dma: fix resource leak in alloc_chan_resources ---
commit d5306db114dcdc27e3a80dfb2bb3a42a91ab9a3a
Author: Logan Gunthorpe <[email protected]>

dmaengine: switchtec-dma: fix resource leak in alloc_chan_resources

This commit fixes a resource leak in switchtec_dma_alloc_chan_resources
by adding an error-unwind path. The new path disables the channel, clears
the active flags, and frees the descriptor rings if an allocation fails.

Link: https://lore.kernel.org/dmaengine/[email protected]
Fixes: 30eba9df76ad ("dmaengine: switchtec-dma: Implement hardware initialization and cleanup")

> diff --git a/drivers/dma/switchtec_dma.c b/drivers/dma/switchtec_dma.c
> index a4a7d66d042de..f77da31aeb65e 100644
> --- a/drivers/dma/switchtec_dma.c
> +++ b/drivers/dma/switchtec_dma.c

[ ... ]

> @@ -1029,6 +1030,20 @@ static int switchtec_dma_alloc_chan_resources(struct dma_chan *chan)
>  		FIELD_GET(PERF_MRRS_MASK, perf_cfg));
>  
>  	return SWITCHTEC_DMA_SQ_SIZE;
> +
> +err_ring_inactive:
> +	spin_lock_bh(&swdma_chan->submit_lock);
> +	swdma_chan->ring_active = false;
> +	spin_unlock_bh(&swdma_chan->submit_lock);
> +
> +	spin_lock_bh(&swdma_chan->complete_lock);
> +	swdma_chan->comp_ring_active = false;
> +	spin_unlock_bh(&swdma_chan->complete_lock);
> +err_disable_channel:
> +	disable_channel(swdma_chan);
> +err_free_desc:
> +	switchtec_dma_free_desc(swdma_chan);

[Severity: High]
If an error occurs in switchtec_dma_alloc_chan_resources() after
unhalt_channel() succeeds (for example, if the RCU pointer check fails),
the unwind path jumps to err_ring_inactive and falls through to
err_disable_channel.

Since disable_channel() only clears a software configuration bit and does
not explicitly issue a hardware halt command or wait for the hardware to
stop processing, could the hardware channel continue performing DMA accesses?

If so, does calling switchtec_dma_free_desc() immediately after
disable_channel() create a window for a DMA use-after-free, where the device
can still read or write into the newly freed coherent memory pages?

> +	return rc;
>  }

[Severity: High]
This is a pre-existing issue, but looking at the driver teardown sequence
in switchtec_dma_remove():

drivers/dma/switchtec_dma.c:switchtec_dma_remove() {
    ...
    switchtec_dma_chans_release(pdev, swdma_dev);
    rcu_assign_pointer(swdma_dev->pdev, NULL);
    synchronize_rcu();
    pci_free_irq(pdev, swdma_dev->chan_status_irq, swdma_dev);
    pci_free_irq_vectors(pdev);
    dma_async_device_unregister(&swdma_dev->dma_dev);
    iounmap(swdma_dev->bar);
    ...
}

Because the resources and MMIO regions are dismantled before the device is
unregistered from the dmaengine core, is it possible for a concurrent
client to call dma_request_chan() and allocate a channel during this window?

If a concurrent allocation finishes right after the channel was freed,
could the client attempt to submit a DMA operation and trigger a kernel
oops when accessing the unmapped MMIO registers?

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=2