DMA Engine development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Rosen Penev" <rosenp@gmail.com>
Cc: vkoul@kernel.org, Frank.Li@kernel.org, dmaengine@vger.kernel.org
Subject: Re: [PATCHv2 2/4] dma: fsl_raid: set final bit via fill_cfd_frame() argument
Date: Thu, 16 Jul 2026 20:47:06 +0000	[thread overview]
Message-ID: <20260716204706.BDE111F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260716202949.677290-3-rosenp@gmail.com>

Thank you for your contribution! Sashiko AI review found 9 potential issue(s) to consider:

New issues:
- [High] Integer underflow leading to wild pointer dereference when src_cnt == 0.
- [Medium] The commit message claims to fix an endianness issue by setting a bit before a 'single cpu_to_be32() store', but this byte-swap is completely missing from the modified code.

Pre-existing issues:
- [High] Multiple severe out-of-bounds writes in `fsl_re_prep_dma_pq()` corrupt the Command Descriptor Block (CDB) when `DMA_PREP_CONTINUE` is set.
- [High] Missing IRQ cleanup leaves the interrupt handler active after module unload.
- [High] Incorrect teardown sequence frees DMA channel resources before unregistering the DMA device.
- [High] Ignored probe failures lead to uninitialized or partially initialized channels being torn down, causing NULL pointer dereferences or double frees.
- [High] Recursive locking deadlock when invoking DMA client callback.
- [High] Race condition due to prematurely enabling interrupts before initialization is complete.
- [High] DMA transfers of exactly 1MB will be silently truncated to 0 bytes due to `FSL_RE_CF_LENGTH_MASK` mismatch.
--

--- Patch [1]: [PATCHv2 2/4] dma: fsl_raid: set final bit via fill_cfd_frame() argument ---
commit 62a6bad1aef1e87fcc87f1d390c2ed3be7152732
Author: Rosen Penev <rosenp@gmail.com>

dma: fsl_raid: set final bit via fill_cfd_frame() argument

The final-frame bit is now passed as the "final" argument of
fill_cfd_frame() (as fsl_re_prep_dma_memcpy already did) and set in CPU
order before the single cpu_to_be32() store, replacing the previous
read-modify-write of the __be32 efrl32 field.

[Severity: Medium]
The commit message claims to fix an endianness issue by setting a bit before
a single cpu_to_be32() store, but this byte-swap appears to be missing from
the modified code.  Looking at fill_cfd_frame() in drivers/dma/fsl_raid.c,
the native integer is assigned directly to the __be32 field:

    cf[index].efrl32 = efrl;

Could this leave the type mismatch unresolved and the endianness bug in
place on little-endian hardware?

> ---
>  drivers/dma/fsl_raid.c | 16 ++++++++--------
>  1 file changed, 8 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/dma/fsl_raid.c b/drivers/dma/fsl_raid.c
> index 99945845d8b5e..a4feaa9a1c628 100644
> --- a/drivers/dma/fsl_raid.c
> +++ b/drivers/dma/fsl_raid.c
> @@ -374,11 +374,11 @@ static struct dma_async_tx_descriptor *fsl_re_prep_dma_genq(
>  	for (i = 2, j = 0; j < save_src_cnt; i++, j++)
>  		fill_cfd_frame(cf, i, len, src[j], 0);
>  
> +	/* Fill the last frame and mark it final */
>  	if (cont_q)
> -		fill_cfd_frame(cf, i++, len, dest, 0);
> -
> -	/* Setting the final bit in the last source buffer frame in CFD */
> -	cf[i - 1].efrl32 |= 1 << FSL_RE_CF_FINAL_SHIFT;
> +		fill_cfd_frame(cf, i, len, dest, 1);
> +	else
> +		fill_cfd_frame(cf, i - 1, len, src[j - 1], 1);

[Severity: High]
Does this code cause an integer underflow when fsl_re_prep_dma_genq() is
called with src_cnt == 0?

If the loop initializing cf frames is completely skipped, j remains 0
(unsigned), causing j - 1 to underflow to UINT_MAX.  This could lead to a
wild pointer dereference when accessing src[j - 1].

>  	return &desc->async_tx;
>  }

[ ... ]

> @@ -504,16 +504,16 @@ static struct dma_async_tx_descriptor *fsl_re_prep_dma_pq(
>  			p[save_src_cnt + 2] = 1;
>  			fill_cfd_frame(cf, i++, len, dest[0], 0);
>  			fill_cfd_frame(cf, i++, len, dest[1], 0);
> -			fill_cfd_frame(cf, i++, len, dest[1], 0);
> +			fill_cfd_frame(cf, i++, len, dest[1], 1);

[Severity: High]
This is a pre-existing issue, but does this continuation path write out of
bounds?

When dmaengine_prep_dma_pq is called with DMA_PREP_CONTINUE and a
src_cnt of 14 to 16, the driver artificially increments src_cnt by 3 (up to
19).  This causes the loop initializing gfm_q1 (and subsequently scf copying)
to overflow the fixed-size 16-byte arrays.

Additionally, the continuation frames are written to cf[19], cf[20], and
cf[21], which overflows the 20-frame limit and can corrupt the adjacent
hardware Command Descriptor Block (CDB) structure.

>  		} else {
>  			dev_err(re_chan->dev, "PQ tx continuation error!\n");
>  			return NULL;
>  		}
> +	} else {
> +		/* Mark the last source buffer frame final */
> +		fill_cfd_frame(cf, i - 1, len, src[j - 1], 1);

[Severity: High]
Similar to the issue in fsl_re_prep_dma_genq(), does this access cause an
integer underflow if fsl_re_prep_dma_pq() is called with src_cnt == 0?

>  	}
>  
> -	/* Setting the final bit in the last source buffer frame in CFD */
> -	cf[i - 1].efrl32 |= 1 << FSL_RE_CF_FINAL_SHIFT;
> -
>  	return &desc->async_tx;
>  }

[ ... ]

[Severity: High]
This is a pre-existing issue, but does fsl_re_remove_chan() leak the
interrupt handler after module unload?

The function kills the tasklet and frees memory, but fails to call
free_irq(chan->irq, chan->dev).  This could leave the ISR active after the
driver is unloaded, potentially causing a use-after-free on the next
hardware interrupt:

drivers/dma/fsl_raid.c:fsl_re_remove_chan() {
    ...
	tasklet_kill(&chan->irqtask);
    ...
}

[Severity: High]
This is a pre-existing issue, but does fsl_re_remove() free DMA channel
resources before unregistering the DMA device?

The teardown sequence iterates over channels to destroy their rings before
notifying the DMA core.  This creates a race condition where a concurrent
client might submit a new DMA request into already freed memory:

drivers/dma/fsl_raid.c:fsl_re_remove() {
    ...
	/* Cleanup chan related memory areas */
	for (i = 0; i < re_priv->total_chans; i++)
		fsl_re_remove_chan(re_priv->re_jrs[i]);
	
	/* Unregister the driver */
	dma_async_device_unregister(&re_priv->dma_dev);
    ...
}

[Severity: High]
This is a pre-existing issue, but does fsl_re_probe() ignore probe failures
and blindly increment the active channel count?

drivers/dma/fsl_raid.c:fsl_re_probe() {
    ...
		if (rc) {
			fsl_re_chan_probe(ofdev, child, ridx++, off);
			re_priv->total_chans++;
		}
    ...
}

If fsl_re_chan_probe() fails, re_jrs[i] remains NULL.  During unload, the
teardown loop unconditionally dereferences it:

drivers/dma/fsl_raid.c:fsl_re_remove() {
    ...
	for (i = 0; i < re_priv->total_chans; i++)
		fsl_re_remove_chan(re_priv->re_jrs[i]);
    ...
}

Could this lead to a NULL pointer dereference in tasklet_kill() if a channel
failed to probe?

[Severity: High]
This is a pre-existing issue, but can fsl_re_dequeue() cause a recursive
locking deadlock if the client submits a new transaction from the callback?

fsl_re_dequeue() acquires desc_lock and holds it while executing the client
callback:

drivers/dma/fsl_raid.c:fsl_re_dequeue() {
    ...
	spin_lock_irqsave(&re_chan->desc_lock, flags);
	...
		fsl_re_desc_done(desc);
    ...
}

If the callback implements request chaining, fsl_re_tx_submit() will attempt
to synchronously re-acquire the exact same desc_lock:

drivers/dma/fsl_raid.c:fsl_re_tx_submit() {
    ...
	spin_lock_irqsave(&re_chan->desc_lock, flags);
    ...
}

[Severity: High]
This is a pre-existing issue, but does fsl_re_chan_probe() enable interrupts
before initialization is complete?

The IRQ is requested before drvdata is persistently linked to the device:

drivers/dma/fsl_raid.c:fsl_re_chan_probe() {
    ...
	ret = request_irq(chan->irq, fsl_re_isr, 0, chan->name, chandev);
	...
	dev_set_drvdata(chandev, chan);
    ...
}

If a pending or spurious interrupt fires immediately, fsl_re_isr() will call
dev_get_drvdata(), which returns NULL, and then dereference it:

drivers/dma/fsl_raid.c:fsl_re_isr() {
    ...
	re_chan = dev_get_drvdata((struct device *)data);

	irqstate = in_be32(&re_chan->jrregs->jr_interrupt_status);
    ...
}

[Severity: High]
This is a pre-existing issue, but does fill_cfd_frame() silently truncate
1MB transfers to 0 bytes?

drivers/dma/fsl_raid.c:fill_cfd_frame() {
    ...
	u32 efrl = length & FSL_RE_CF_LENGTH_MASK;
    ...
}

FSL_RE_MAX_DATA_LEN is defined as 1024*1024 (0x100000), allowing exactly 1MB.
However, if FSL_RE_CF_LENGTH_MASK is 0x000FFFFF (20 bits), the bitwise-AND
operation will silently truncate a 1MB transfer to 0.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260716202949.677290-3-rosenp@gmail.com?part=1

  reply	other threads:[~2026-07-16 20:47 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-16 20:29 [PATCHv2 0/4] dma: fsl_raid: fix sparse warnings and simplify probing Rosen Penev
2026-07-16 20:29 ` [PATCHv2 1/4] dma: fsl_raid: convert descriptor stores to big-endian Rosen Penev
2026-07-16 20:44   ` sashiko-bot
2026-07-16 20:49   ` Frank Li
2026-07-16 20:29 ` [PATCHv2 2/4] dma: fsl_raid: set final bit via fill_cfd_frame() argument Rosen Penev
2026-07-16 20:47   ` sashiko-bot [this message]
2026-07-16 20:57   ` Frank Li
2026-07-16 20:29 ` [PATCHv2 3/4] dma: fsl_raid: keep MMIO bases as void __iomem and cast at access Rosen Penev
2026-07-16 20:44   ` sashiko-bot
2026-07-16 21:02   ` Frank Li
2026-07-16 20:29 ` [PATCHv2 4/4] dma: fsl_raid: use devm_platform_ioremap_resource Rosen Penev

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=20260716204706.BDE111F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=Frank.Li@kernel.org \
    --cc=dmaengine@vger.kernel.org \
    --cc=rosenp@gmail.com \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=vkoul@kernel.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox