Re: [PATCH RESEND v5] dmaengine: sun6i-dma: Fix use-after-free in error handling paths
[email protected] Mon, 27 Jul 2026 06:24:37 +0000
| Newsgroups | dev.linux.lists.linux-sunxi,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 input validation in `sun6i_dma_prep_dma_cyclic()` leads to a divide-by-zero panic or a NULL pointer dereference when setting up the cyclic list. - [High] Failing to validate `sg_len > 0` in `sun6i_dma_prep_slave_sg()` allows submission of an empty descriptor, leading to a hardware fault. - [High] A race condition in `sun6i_dma_tx_status()` leads to a Use-After-Free when querying the status of a transfer. -- --- Patch [1]: [PATCH RESEND v5] dmaengine: sun6i-dma: Fix use-after-free in error handling paths --- commit f42009e17697997cd6fc8eda0aef5712caa48d76 Author: Hongling Zeng <[email protected]> Subject: dmaengine: sun6i-dma: Fix use-after-free in error handling paths This commit fixes a use-after-free in the error handling paths of the sun6i-dma driver by refactoring the descriptor cleanup into a new helper function. It also introduces a virtual descriptor freeing helper for vchan. > diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c > index a9a254dbf8cb9..7a79f346250a5 100644 > --- a/drivers/dma/sun6i-dma.c > +++ b/drivers/dma/sun6i-dma.c [ ... ] > @@ -788,10 +795,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg( > return vchan_tx_prep(&vchan->vc, &txd->vd, flags); > > err_lli_free: [Severity: High] This isn't a bug introduced by this patch, but does the validation in sun6i_dma_prep_slave_sg() need to check for empty scatterlists? The function checks if the scatterlist pointer is valid: if (!sgl) return NULL; However, if sg_len is 0, the for_each_sg() loop is bypassed entirely. This leaves txd->p_lli as 0. When this descriptor is later executed by sun6i_dma_start_desc(), the hardware LLI address register is programmed with physical address 0: writel(pchan->desc->p_lli, pchan->base + DMA_CHAN_LLI_ADDR); Could this cause a hardware fault by instructing the DMA controller to fetch its configuration from physical address 0? > - for (p_lli = txd->p_lli, v_lli = txd->v_lli; v_lli; > - p_lli = v_lli->p_lli_next, v_lli = v_lli->v_lli_next) > - dma_pool_free(sdev->pool, v_lli, p_lli); > - kfree(txd); > + sun6i_dma_free_desc(sdev, txd); > return NULL; > } [ ... ] > @@ -869,10 +873,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic( > return vchan_tx_prep(&vchan->vc, &txd->vd, flags); > > err_lli_free: [Severity: High] This is a pre-existing issue, but I noticed a potential divide-by-zero and NULL pointer dereference in sun6i_dma_prep_dma_cyclic(). If a caller passes period_len as 0, does this calculation cause a divide-by-zero exception? unsigned int i, periods = buf_len / period_len; Additionally, if buf_len is less than period_len, periods evaluates to 0. This skips the allocation loop entirely, leaving the prev pointer uninitialized (NULL). Would the subsequent attempt to make the list cyclic cause a NULL pointer dereference? prev->p_lli_next = txd->p_lli; > - for (p_lli = txd->p_lli, v_lli = txd->v_lli; v_lli; > - p_lli = v_lli->p_lli_next, v_lli = v_lli->v_lli_next) > - dma_pool_free(sdev->pool, v_lli, p_lli); > - kfree(txd); > + sun6i_dma_free_desc(sdev, txd); > return NULL; > } [ ... ] [Severity: High] This is a pre-existing issue, but I noticed a potential race condition when querying the status of a transfer. In sun6i_dma_tx_status(), the function queries dma_cookie_status() outside the channel lock: ret = dma_cookie_status(chan, cookie, state); If the cookie status is DMA_IN_PROGRESS, can the thread be preempted before taking the lock? During this window, the hardware interrupt could fire, completing the transfer and triggering the vchan_complete tasklet which frees the descriptor memory. When sun6i_dma_tx_status() resumes and acquires the lock, it might fail to find the descriptor in the pending lists and fall back to calculating the size using the active physical channel state: bytes = sun6i_get_chan_size(pchan); Inside sun6i_get_chan_size(), this would dereference the freed descriptor: pos = pchan->desc->p_lli; Since pchan->desc is cleared by sun6i_dma_tasklet running sequentially afterwards, could this lead to a use-after-free? -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=1