Re: [PATCH v2 43/64] dmaengine: pxa_dma: kill vchan BH on teardown

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

Pre-existing issues:
- [High] Prematurely deleting channels from `dmadev->channels` during driver removal bypasses the dmaengine core's unregistration logic, permanently breaking module reload.
- [High] Critical Use-After-Free vulnerability on driver unbind due to improper devres cleanup ordering and failure to quiesce the hardware.
- [High] Missing `of_dma_controller_free()` on driver removal leaves a dangling pointer in the OF DMA list.
- [High] Potential Use-After-Free on the probe error path due to missing synchronization of bottom-half work.
--

--- Patch [43]: [PATCH v2 43/64] dmaengine: pxa_dma: kill vchan BH on teardown ---
commit 542f54f4e01925d8e48b9a9c649593d23bb50a91
Author: Allen Pais <[email protected]>

dmaengine: pxa_dma: kill vchan BH on teardown

Use dma_chan_kill_bh() for virt-dma cleanup.

> diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c
> index fa2ee0b3e09f8..d57e5e0c422cb 100644
> --- a/drivers/dma/pxa_dma.c
> +++ b/drivers/dma/pxa_dma.c
> @@ -1215,7 +1215,7 @@ static void pxad_free_channels(struct dma_device *dmadev)
>  	list_for_each_entry_safe(c, cn, &dmadev->channels,
>  				 vc.chan.device_node) {
>  		list_del(&c->vc.chan.device_node);

[Severity: High]
This is a pre-existing issue, but does this premature list deletion bypass the
dmaengine core's unregistration logic?

In pxad_remove(), the driver calls pxad_free_channels(), which uses list_del()
to manually remove each channel from dmadev->channels. The core framework's
dma_async_device_unregister() is executed subsequently as a devres action and
relies on traversing dmadev->channels to unregister each channel.

Because the list has been artificially emptied,
__dma_async_device_channel_unregister() is never invoked, skipping
device_unregister(), ida_free(), and free_percpu(). Will this leak sysfs
nodes (e.g., "dma0chan0") and cause permanent sysfs name collisions on
subsequent module loads?

> -		tasklet_kill(&c->vc.task);
> +		dma_chan_kill_bh(&c->vc.chan);
>  	}
>  }

[Severity: High]
This is a pre-existing issue, but is there a use-after-free vulnerability on
driver unbind due to improper devres cleanup ordering?

During initialization, pxad_init_phys() requests IRQs via devm_request_irq(),
and subsequently pxad_init_dmadev() allocates channel memory via
devm_kzalloc(). Because devres releases resources in reverse order, the channel
memory is freed before the IRQ is released.

Since pxad_remove() fails to mask interrupts or explicitly stop the DMA
hardware, if the hardware asserts an interrupt during this window:

drivers/dma/pxa_dma.c:pxad_chan_handler() {
    ...
    struct pxad_chan *chan = phy->vchan;
    ...
    spin_lock(&chan->vc.lock);
    ...
}

Will this dereference the already freed phy->vchan pointer and attempt to
acquire a freed spinlock if an interrupt fires during teardown?

[Severity: High]
This is also a pre-existing issue, but does driver removal leave a dangling
pointer in the OF DMA list?

In pxad_probe(), the driver registers its DMA controller using
of_dma_controller_register(), adding an of_dma structure to the global
of_dma_list. However, neither pxad_remove() nor any error path calls
of_dma_controller_free().

When the driver is unbound, will the of_dma structure remain in the global
list, containing pointers to the freed pdev memory and the unloaded
pxad_dma_xlate code, leading to a use-after-free if subsequent DMA requests
from other devices traverse the DT?

[Severity: High]
This is a pre-existing issue, but is there a potential use-after-free on the
probe error path due to missing synchronization of bottom-half work?

In pxad_probe(), if of_dma_controller_register() fails, the function returns
an error without flushing bottom-half work:

drivers/dma/pxa_dma.c:pxad_probe() {
    ...
    if (ret < 0) {
        dev_err(pdev->slave.dev,
                "of_dma_controller_register failed\n");
        return ret;
    }
    ...
}

Because dmaenginem_async_device_register() executes prior to this failure, the
DMA controller is briefly globally visible. If an external client requests a
channel and queues bh_work during this window, will the devres cleanup free
the channel memory before the asynchronous work executes?

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