From: Hongling Zeng <zhongling0719@126.com>
To: Frank Li <Frank.li@oss.nxp.com>,
Hongling Zeng <zenghongling@kylinos.cn>
Cc: ludovic.desroches@microchip.com, vkoul@kernel.org,
Frank.Li@kernel.org, tudor.ambarus@linaro.org,
nicolas.ferre@microchip.com,
linux-arm-kernel@lists.infradead.org, dmaengine@vger.kernel.org,
linux-kernel@vger.kernel.org, sashiko-bot@kernel.org
Subject: Re: [PATCH v4] dma: at_hdmac: Fix use-after-free by proper tasklet cleanup
Date: Thu, 09 Jul 2026 10:39:36 +0800 [thread overview]
Message-ID: <6A4F09E8.8040807@126.com> (raw)
In-Reply-To: <ak7B5gxc9LrMmxO4@SMW015318>
在 2026年07月09日 05:32, Frank Li 写道:
> On Wed, Jul 08, 2026 at 10:59:59AM +0800, Hongling Zeng wrote:
>> Current cleanup paths have a use-after-free vulnerability:
>> - vchan_init() creates tasklets that access at_dma_chan memory
>> - free_irq() only waits for IRQ handler, NOT tasklets
>> - atdma is devm-managed and freed after probe/remove
>> - Running tasklets accessing freed memory → Use-After-Free!
>>
>> The fix requires careful ordering:
>> - free_irq() FIRST to synchronize with running IRQ handlers and prevent
>> them from scheduling new tasklets
>> - Then kill tasklets to wait for already-scheduled ones to complete
>> - Only then free other resources
>>
>> Fixes: ac803b56860f ("dmaengine: at_hdmac: Convert driver to use virt-dma")
>> Reported-by: sashiko-bot@kernel.org
>> Closes: https://lore.kernel.org/all/20260604073945.54B311F00898@smtp.kernel.org/
>> Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
>>
>> ---
>> Change in v4:
>> - Fix error path fallthrough causing double-free_irq()
>> - Use channel iteration index (chan_id not initialized before registration)
>> - Remove unnecessary defensive checks
>> ---
>> drivers/dma/at_hdmac.c | 31 ++++++++++++++++++++++---------
>> 1 file changed, 22 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
>> index e5b30a57c477..044a0fb38b7a 100644
>> --- a/drivers/dma/at_hdmac.c
>> +++ b/drivers/dma/at_hdmac.c
>> @@ -1940,6 +1940,20 @@ static void at_dma_off(struct at_dma *atdma)
>> cpu_relax();
>> }
>>
>> +static void at_dma_cleanup_channels(struct at_dma *atdma)
>> +{
>> + struct dma_chan *chan, *_chan;
>> + int i = 0;
>> +
>> + list_for_each_entry_safe(chan, _chan, &atdma->dma_device.channels,
>> + device_node) {
>> + /* Disable interrupts */
>> + atc_disable_chan_irq(atdma, i++);
>> + tasklet_kill(&to_at_dma_chan(chan)->vc.task);
>> + list_del(&chan->device_node);
>> + }
>> +}
>> +
>> static int __init at_dma_probe(struct platform_device *pdev)
>> {
>> struct at_dma *atdma;
>> @@ -2105,12 +2119,17 @@ static int __init at_dma_probe(struct platform_device *pdev)
>> err_of_dma_controller_register:
>> dma_async_device_unregister(&atdma->dma_device);
>> err_dma_async_device_register:
>> + free_irq(platform_get_irq(pdev, 0), atdma);
>> + at_dma_cleanup_channels(atdma);
>> dma_pool_destroy(atdma->memset_pool);
>> + dma_pool_destroy(atdma->lli_pool);
>> + goto err_clk;
> I forget the reason why need goto here. Can you call disable_irq() or
> disable hardware irq and call synchronize_irq() at free_irq() place. then
> goto can fallback to below clean up code
>
> Frank
Thank you for the suggestion. I've updated to v6 following your advice:
- Replaced free_irq() with disable_irq() to allow fallthrough without
goto
- free_irq() is now called only once at err_desc_pool_create label
The new approach ensures IRQ handler cannot schedule tasklets before
tasklet_kill(), then free_irq() handles the actual release.
Please help to review again.
Thanks!
>
>> err_memset_pool_create:
>> dma_pool_destroy(atdma->lli_pool);
>> err_desc_pool_create:
>> free_irq(platform_get_irq(pdev, 0), atdma);
>> err_irq:
>> +err_clk:
>> clk_disable_unprepare(atdma->clk);
>> return err;
>> }
>> @@ -2118,23 +2137,17 @@ static int __init at_dma_probe(struct platform_device *pdev)
>> static void at_dma_remove(struct platform_device *pdev)
>> {
>> struct at_dma *atdma = platform_get_drvdata(pdev);
>> - struct dma_chan *chan, *_chan;
>>
>> at_dma_off(atdma);
>> if (pdev->dev.of_node)
>> of_dma_controller_free(pdev->dev.of_node);
>> dma_async_device_unregister(&atdma->dma_device);
>>
>> - dma_pool_destroy(atdma->memset_pool);
>> - dma_pool_destroy(atdma->lli_pool);
>> free_irq(platform_get_irq(pdev, 0), atdma);
>>
>> - list_for_each_entry_safe(chan, _chan, &atdma->dma_device.channels,
>> - device_node) {
>> - /* Disable interrupts */
>> - atc_disable_chan_irq(atdma, chan->chan_id);
>> - list_del(&chan->device_node);
>> - }
>> + at_dma_cleanup_channels(atdma);
>> + dma_pool_destroy(atdma->memset_pool);
>> + dma_pool_destroy(atdma->lli_pool);
>>
>> clk_disable_unprepare(atdma->clk);
>> }
>> --
>> 2.25.1
>>
prev parent reply other threads:[~2026-07-09 2:40 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-08 2:59 [PATCH v4] dma: at_hdmac: Fix use-after-free by proper tasklet cleanup Hongling Zeng
2026-07-08 21:32 ` Frank Li
2026-07-09 2:39 ` Hongling Zeng [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=6A4F09E8.8040807@126.com \
--to=zhongling0719@126.com \
--cc=Frank.Li@kernel.org \
--cc=Frank.li@oss.nxp.com \
--cc=dmaengine@vger.kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=ludovic.desroches@microchip.com \
--cc=nicolas.ferre@microchip.com \
--cc=sashiko-bot@kernel.org \
--cc=tudor.ambarus@linaro.org \
--cc=vkoul@kernel.org \
--cc=zenghongling@kylinos.cn \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.