Re: [PATCH v2 17/64] dmaengine: ste_dma40: convert per-channel tasklet to dma_chan BH
[email protected] Mon, 27 Jul 2026 21:00:50 +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] Missing `free_irq()` on `d40_probe` error paths leads to a leaked IRQ handler and a potential Use-After-Free of `base`. - [High] Missing `device_synchronize` callback causes a race condition during channel release, potentially invoking callbacks in unloaded client modules. - [High] Probe failure after exposing channels causes a Use-After-Free because devres forcefully frees memory while clients or scheduled BH work may be active. -- --- Patch [17]: [PATCH v2 17/64] dmaengine: ste_dma40: convert per-channel tasklet to dma_chan BH --- commit 7d6ec649e7f14a8affbdbde4ad9aa8498383284e Author: Allen Pais <[email protected]> Subject: dmaengine: ste_dma40: convert per-channel tasklet to dma_chan BH This commit replaces the per-channel tasklet with the shared dma_chan BH helper. The handler continues to run in softirq context while dmaengine manages the scheduling and teardown mechanism. > diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c > index 0d9ffa3e26639..f279a093a81f6 100644 > --- a/drivers/dma/ste_dma40.c > +++ b/drivers/dma/ste_dma40.c [ ... ] > @@ -1641,7 +1638,7 @@ static void dma_tasklet(struct tasklet_struct *t) > d40c->pending_tx--; > > if (d40c->pending_tx) > - tasklet_schedule(&d40c->tasklet); > + dma_chan_schedule_bh(&d40c->chan); > > spin_unlock_irqrestore(&d40c->lock, flags); > [Severity: High] This is a pre-existing issue, but does this create a race condition during channel release? The driver doesn't seem to implement the device_synchronize callback, making dmaengine_synchronize() a no-op. When a DMA client module unloads and releases its channel, it relies on this synchronization to flush any pending async work. Could dma_release_channel() return and the client module unload while the bh_work is still executing here? If the work is preempted right after dropping the channel lock and before invoking the client callback: spin_unlock_irqrestore(&d40c->lock, flags); if (callback_active) dmaengine_desc_callback_invoke(&cb, NULL); wouldn't it resume and attempt to execute the callback residing in the now-freed module's .text segment? Additionally, I noticed a couple of pre-existing issues in d40_probe(): [Severity: High] This isn't a bug introduced by this patch, but does d40_probe() leak the IRQ handler on error paths? drivers/dma/ste_dma40.c:d40_probe() { ... ret = request_irq(base->irq, d40_handle_interrupt, 0, D40_NAME, base); if (ret) { d40_err(dev, "No IRQ defined\n"); goto destroy_cache; } ... if (base->plat_data->use_esram_lcla) { base->lcpa_regulator = regulator_get(base->dev, "lcla_esram"); if (IS_ERR(base->lcpa_regulator)) { d40_err(dev, "Failed to get lcpa_regulator\n"); ret = PTR_ERR(base->lcpa_regulator); base->lcpa_regulator = NULL; goto destroy_cache; } ... destroy_cache: if (base->lcla_pool.dma_addr) dma_unmap_single(...) ... report_failure: d40_err(dev, "probe failed\n"); return ret; } If d40_probe() fails after request_irq() (for example, in regulator_enable() or of_dma_controller_register()), it branches to the destroy_cache label and returns an error without freeing the registered IRQ. Because base is automatically freed by the devres framework, if a spurious or lingering interrupt fires afterwards, won't the still-registered d40_handle_interrupt() execute and dereference the freed base pointer? [Severity: High] This isn't a bug introduced by this patch, but does a probe failure after exposing channels cause a Use-After-Free? drivers/dma/ste_dma40.c:d40_probe() { ... ret = d40_dmaengine_init(base, num_reserved_chans); if (ret) goto destroy_cache; ... ret = of_dma_controller_register(np, d40_xlate, NULL); if (ret) { dev_err(dev, "could not register of_dma_controller\n"); goto destroy_cache; } ... } In d40_probe(), the driver exposes channels globally by calling dmaenginem_async_device_register() midway through the function via d40_dmaengine_init(). If a subsequent initialization step fails, like of_dma_controller_register(), the function returns an error. The devres framework then automatically unregisters the DMA device and frees the driver's memory. In the window between registration and failure, could a concurrent client driver request a channel and start a transfer, or an interrupt fire and schedule the channel's BH work? Since dma_async_device_unregister() doesn't wait for active clients to drop references when called from devres, will the client or BH work access the forcefully freed structures? -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=17