Re: [PATCH v2 37/64] dmaengine: idma64: kill vchan BH on teardown

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

Pre-existing issues:
- [High] The channel cleanup loop in idma64_remove() is dead code, leading to a Use-After-Free of bottom-half work items.
- [High] A race condition during device removal can cause an unhandled interrupt storm.
- [High] Use-After-Free due to missing device_release callback with devres-managed core structure.
--

--- Patch [37]: [PATCH v2 37/64] dmaengine: idma64: kill vchan BH on teardown ---
commit e368659298f3842bf78bcfc4c53afeb968ac845c
Author: Allen Pais <[email protected]>

dmaengine: idma64: kill vchan BH on teardown

Use dma_chan_kill_bh() for virt-dma cleanup.

> diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c
> index 5fcd1befc92da..8e25d828e553d 100644
> --- a/drivers/dma/idma64.c
> +++ b/drivers/dma/idma64.c
> @@ -617,14 +617,14 @@ static void idma64_remove(struct idma64_chip *chip)
>  
>  	/*
>  	 * Explicitly call devm_request_irq() to avoid the side effects with
> -	 * the scheduled tasklets.
> +	 * scheduled BH work.
>  	 */
>  	devm_free_irq(chip->dev, chip->irq, idma64);

[Severity: High]
This is a pre-existing issue, but does calling devm_free_irq() after
dma_async_device_unregister() create a race condition that can cause an
interrupt storm?

The earlier call to dma_async_device_unregister() iterates over the channels
and decrements idma64->dma.chancnt to 0.

If a hardware interrupt triggers in the narrow window before devm_free_irq()
disables it, idma64_irq() executes this loop:

idma64_irq() {
    ...
    for (i = 0; i < idma64->dma.chancnt; i++)
        idma64_chan_irq(idma64, i, status_err, status_xfer);
    ...
}

Because chancnt is 0, it skips clearing the active hardware interrupt but
still returns IRQ_HANDLED. Will the hardware continually re-assert the
uncleared interrupt and hang the CPU?

>  
>  	for (i = 0; i < idma64->dma.chancnt; i++) {
>  		struct idma64_chan *idma64c = &idma64->chan[i];
>  
> -		tasklet_kill(&idma64c->vchan.task);
> +		dma_chan_kill_bh(&idma64c->vchan.chan);
>  	}
>  }

[Severity: High]
This is a pre-existing issue, but will this cleanup loop ever execute?

Since the preceding call to dma_async_device_unregister() decrements
idma64->dma.chancnt to 0 before we reach this loop, the loop is completely
skipped and dma_chan_kill_bh() is never called.

When devres subsequently frees the idma64 structure, won't any pending
bottom-half work items execute on freed memory?

[Severity: High]
This is also a pre-existing issue, but is there a use-after-free risk because
struct idma64 is allocated with devm_kzalloc() but lacks a
dma_device->device_release callback?

When the driver unbinds and idma64_remove() completes, devres will
automatically free the idma64 structure:

idma64_probe() {
    ...
    idma64 = devm_kzalloc(chip->dev, sizeof(*idma64), GFP_KERNEL);
    ...
}

If a DMA client still holds a reference to a channel, won't the client
dereference the freed idma64 memory when accessing or releasing the channel
later, since the DMA core manages reference counts via device->ref?

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