Re: [PATCH] dmaengine: sun6i: fix use-after-free in descriptor error path

[email protected]
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 validation for `period_len` and `buf_len` in `sun6i_dma_prep_dma_cyclic` leads to a division by zero or a NULL pointer dereference.
- [High] Missing validation for `sg_len == 0` in `sun6i_dma_prep_slave_sg` leads to hardware being programmed with physical address 0x0.
- [High] Integer truncation in the interrupt handler loop bound causes interrupts from channels >= 8 to be permanently ignored on SoCs with non-multiple-of-8 channels (e.g., sun8i-h3).
--

--- Patch [1]: [PATCH] dmaengine: sun6i: fix use-after-free in descriptor error path ---
commit 815343fddc5f554759b857f782dbda4a7c8b1a7a
Author: Chaithanya Lagisetty <[email protected]>

dmaengine: sun6i: fix use-after-free in descriptor error path

The err_lli_free cleanup loops in sun6i_dma_prep_slave_sg() and
sun6i_dma_prep_dma_cyclic() free each LLI node with dma_pool_free()
and then dereference the freed node to obtain v_lli_next and
p_lli_next for the next loop iteration.

> diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
> index a9a254dbf8cb9..2c163ab22af5c 100644
> --- a/drivers/dma/sun6i-dma.c
> +++ b/drivers/dma/sun6i-dma.c
> @@ -720,10 +720,10 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
>  	struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
>  	struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
>  	struct dma_slave_config *sconfig = &vchan->cfg;
> -	struct sun6i_dma_lli *v_lli, *prev = NULL;
> +	struct sun6i_dma_lli *v_lli, *v_next, *prev = NULL;
>  	struct sun6i_desc *txd;
>  	struct scatterlist *sg;
> -	dma_addr_t p_lli;
> +	dma_addr_t p_lli, p_next;
>  	u32 lli_cfg;
>  	int i, ret;
>  

[Severity: High]
This is a pre-existing issue, but I noticed there is no validation for
sg_len == 0.

If a caller provides an empty scatterlist, the txd is allocated but the
for_each_sg() loop is skipped:

drivers/dma/sun6i-dma.c:sun6i_dma_prep_slave_sg() {
    ...
    for_each_sg(sgl, sg, sg_len, i) {
        ...
    }
    ...
}

This leaves txd->p_lli as 0 and txd->v_lli as NULL. When this descriptor is
executed via sun6i_dma_start_desc(), the hardware is programmed with physical
address 0x0.

Could this lead to the hardware accessing physical address 0x0?

[ ... ]

> @@ -806,9 +809,9 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
>  	struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
>  	struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
>  	struct dma_slave_config *sconfig = &vchan->cfg;
> -	struct sun6i_dma_lli *v_lli, *prev = NULL;
> +	struct sun6i_dma_lli *v_lli, *v_next, *prev = NULL;
>  	struct sun6i_desc *txd;
> -	dma_addr_t p_lli;
> +	dma_addr_t p_lli, p_next;
>  	u32 lli_cfg;
>  	unsigned int i, periods = buf_len / period_len;

[Severity: High]
This is a pre-existing issue, but is it possible for period_len to be 0 here,
leading to a division by zero?

Additionally, if buf_len < period_len, periods evaluates to 0, which skips
the allocation loop. This leaves prev as NULL, and causes a NULL pointer
dereference later in the function:

drivers/dma/sun6i-dma.c:sun6i_dma_prep_dma_cyclic() {
    ...
    prev->p_lli_next = txd->p_lli;      /* cyclic list */
    ...
}

Should we validate period_len and buf_len before performing this division?

[ ... ]

While reviewing this code, I also noticed another pre-existing issue in the
interrupt handler.

[Severity: High]
This is a pre-existing issue, but I noticed a potential truncation in the
channel group calculation for the interrupt handler.

drivers/dma/sun6i-dma.c:sun6i_dma_interrupt() {
    ...
    for (i = 0; i < sdev->num_pchans / DMA_IRQ_CHAN_NR; i++) {
        ...
    }
    ...
}

For SoCs with non-multiple-of-8 channel counts (like sun8i-h3 with 12
channels), 12 / 8 evaluates to 1. This causes the handler to only process
channels 0-7 and completely skip channels 8-11.

Could this result in unhandled interrupts and system hard lockups if a DMA
transfer completes on channels 8-11?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.