Re: [PATCH v2 59/64] dmaengine: tegra186-gpc: use dma_chan_kill_bh
[email protected] Mon, 27 Jul 2026 21:23:48 +0000
| Newsgroups | org.kernel.vger.dmaengine |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider: Pre-existing issues: - [Critical] Zero-length DMA requests cause an integer underflow when calculating the hardware word count, resulting in an unbounded 4GB DMA transfer. - [High] TOCTOU race condition in the interrupt handler `tegra_dma_isr` leading to a Use-After-Free of `dma_desc`. - [High] Incorrect teardown order in `tegra_dma_free_chan_resources()` allows late interrupts to reschedule the channel bottom-half, leading to a Use-After-Free. - [High] Ignored error return from `tegra_dma_terminate_all()` leads to descriptor memory leak and active hardware DMA during channel teardown. - [High] An unsupported DMA slave bus width causes `get_transfer_param()` to silently propagate an error code (-EINVAL) into the DMA hardware's MMIO sequence register. -- --- Patch [59]: [PATCH v2 59/64] dmaengine: tegra186-gpc: use dma_chan_kill_bh --- commit a9e2657d46f0ef7a89cb50bf6bca1e73ae39ee11 Author: Allen Pais <[email protected]> dmaengine: tegra186-gpc: use dma_chan_kill_bh virt-dma now dispatches completion callbacks through per-channel BH work instead of its tasklet. Cancel that work during teardown before channel storage is released. > diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c > index 64cedef1050ae..1ba8897ec614e 100644 > --- a/drivers/dma/tegra186-gpc-dma.c > +++ b/drivers/dma/tegra186-gpc-dma.c > @@ -1284,7 +1284,7 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc) > tegra_dma_terminate_all(dc); [Severity: High] This isn't a bug introduced by this patch, but should we check the return value of tegra_dma_terminate_all() here? If tegra_dma_terminate_all() fails due to a hardware timeout, it returns early without moving the active descriptor to the terminated list and without disabling the hardware. Since the caller ignores the return value, vchan_free_chan_resources() might fail to locate and free the active descriptor. Could this leave the hardware executing a transfer into client memory that may be subsequently freed? > synchronize_irq(tdc->irq); > > - tasklet_kill(&tdc->vc.task); > + dma_chan_kill_bh(&tdc->vc.chan); [Severity: High] This is a pre-existing issue, but does killing the bottom-half before freeing the IRQ expose a race window? If the DMA hardware remains active after a timeout, and dma_chan_kill_bh() is called before free_irq(), could a late interrupt fire and invoke vchan_cookie_complete() or vchan_cyclic_callback()? This would re-queue the bottom-half work. After vchan_free_chan_resources() subsequently frees all descriptors, the queued bottom-half might execute and dereference the freed memory. > tdc->config_init = false; > tdc->slave_id = -1; > tdc->sid_dir = DMA_TRANS_NONE; While reviewing the file, I noticed a few other pre-existing issues: [Severity: High] This isn't a bug introduced by this patch, but does tegra_dma_isr() have a race condition leading to a use-after-free of dma_desc? drivers/dma/tegra186-gpc-dma.c:tegra_dma_isr() { ... struct tegra_dma_desc *dma_desc = tdc->dma_desc; ... spin_lock_irqsave(&tdc->vc.lock, flags); ... if (!dma_desc) goto irq_done; ... } The shared descriptor pointer is cached into a local variable before acquiring the spinlock. If the ISR is delayed while another CPU calls tegra_dma_terminate_all(), the descriptor is freed. Could a subsequent DMA transfer quickly trigger another interrupt, causing the delayed ISR to acquire the lock, pass the check, and dereference the stale local pointer? [Severity: High] This is a pre-existing issue, but do zero-length DMA requests cause an integer underflow when calculating the hardware word count? In tegra_dma_prep_dma_memset(): drivers/dma/tegra186-gpc-dma.c:tegra_dma_prep_dma_memset() { ... sg_req[0].wcount = ((len - 4) >> 2); ... } The same calculation exists in tegra_dma_prep_dma_memcpy() and tegra_dma_prep_slave_sg(). If a client requests a 0-length DMA transfer, the length checks appear to pass. The computation then underflows to 0x3FFFFFFF. Because the hardware interprets this as N+1 words, could this trigger an unbounded 4GB DMA transfer? [Severity: High] This isn't a bug introduced by this patch, but does get_transfer_param() silently propagate an error code to the MMIO sequence register? drivers/dma/tegra186-gpc-dma.c:get_transfer_param() { ... *mmio_seq = get_bus_width(tdc, tdc->dma_sconfig.dst_addr_width); *burst_size = tdc->dma_sconfig.dst_maxburst; *slave_bw = tdc->dma_sconfig.dst_addr_width; *csr = TEGRA_GPCDMA_CSR_DMA_MEM2IO_FC; return 0; } If a client configures an unsupported dst_addr_width, get_bus_width() returns -EINVAL. This negative error code is assigned directly to *mmio_seq, and the function still returns 0 for success. Could this signed error be bitwise-ORed with other flags and written directly to the hardware register, corrupting the configuration bitfields? -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=59