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: [PATCHv3] dmaengine: fsl_raid: free resources in probe
Date: Thu, 10 Sep 2026 20:30:07 +0000	[thread overview]
Message-ID: <20260910203007.F22801F000FF@smtp.kernel.org> (raw)
In-Reply-To: <20260910201556.44207-1-rosenp@gmail.com>

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

New issues:
- [High] Double-Free of IRQ and Use-After-Free of platform device due to ignored error unwind path.
- [High] Incorrect error unwind order creates a Use-After-Free race condition.

Pre-existing issues:
- [Critical] Resource Leak and Use-After-Free on subsequent channel probe failure.
- [Critical] Inverted High/Low physical address programming for DMA rings.
- [High] NULL Pointer Dereference during teardown if channel probe fails early.
- [High] Premature IRQ enablement leading to uninitialized lock and list usage.
- [High] Deadlock in DMA callback execution.
- [High] Use-After-Free due to destroying resources before unregistering the DMA device.
- [High] Missing DMA channel registration renders the driver completely useless.
--

commit 201959b3fc32827578294d7c04cb951e0865cc39
Author: Rosen Penev <rosenp@gmail.com>

    dmaengine: fsl_raid: free resources in probe
    
    Add free_irq() in the error unwind of fsl_re_chan_probe() and in
    fsl_re_remove_chan() so the interrupt is always released.
    
    Also add tasklet_kill(). Present in _remove but not _probe.
    
    Also add of_platform_device_destroy() on failure as
    of_platform_device_create() increases the reference count and needs
    of_platform_device_destroy() on failure. Requires placing the pointer in
    the struct for the _remove function.
    
    Fixes: ad80da658bbc ("dmaengine: Driver support for FSL RaidEngine device.")
    Assisted-by: opencode:hy3-free
    Signed-off-by: Rosen Penev <rosenp@gmail.com>

> diff --git a/drivers/dma/fsl_raid.c b/drivers/dma/fsl_raid.c
> index 2d86f61105e52..a5b9325028f5f 100644
> --- a/drivers/dma/fsl_raid.c
> +++ b/drivers/dma/fsl_raid.c
> @@ -669,14 +668,13 @@ static int fsl_re_chan_probe(struct platform_device *ofdev,
>  
>  	snprintf(chan->name, sizeof(chan->name), "re_jr%02d", q);
>  
> -	chandev = &chan_ofdev->dev;
>  	tasklet_setup(&chan->irqtask, fsl_re_dequeue);
>  
> -	ret = request_irq(chan->irq, fsl_re_isr, 0, chan->name, chandev);
> +	ret = request_irq(chan->irq, fsl_re_isr, 0, chan->name, chan);

[Severity: High]
This is a pre-existing issue, but does requesting the IRQ here make the
interrupt handler live before subsequent initialization steps?

These important structures are initialized too late:

drivers/dma/fsl_raid.c:fsl_re_chan_probe() {
    ...
	spin_lock_init(&chan->desc_lock);
	INIT_LIST_HEAD(&chan->ack_q);
	INIT_LIST_HEAD(&chan->active_q);
    ...
}

Can this cause a kernel crash due to uninitialized spinlock and list
operations if the hardware has a pending interrupt from a previous boot or
kexec when the driver probes?

>  	if (ret) {
>  		dev_err(dev, "Unable to register interrupt for JR %d\n", q);
>  		ret = -EINVAL;
> -		goto err_free;
> +		goto err_free_tasklet;
>  	}
>  
>  	re_priv->re_jrs[q] = chan;

[Severity: High]
If fsl_re_chan_probe() fails after this assignment, the channel pointer is
stored in the driver's private array before the final allocations occur. If
those allocations fail, doesn't this leave a dangling pointer?

Later in fsl_re_probe(), the return value of fsl_re_chan_probe() is ignored:

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

So the driver commits the failed channel to the active channel count.

When the driver is subsequently removed, fsl_re_remove_chan() will be called
again for the already freed channel. Since this patch adds free_irq() and
of_platform_device_destroy() to the error unwind path, will this result in a
double-free of the IRQ and a use-after-free of the platform device?


[Severity: High]
This is a pre-existing issue, but while the driver properly assigns the
framework device pointers:

drivers/dma/fsl_raid.c:fsl_re_chan_probe() {
    ...
	chan->chan.device = dma_dev;
	chan->chan.private = chan;
    ...
}

It seems to fail to link the channel into the framework's channels list.
Does this missing DMA channel registration render the driver completely useless
by silently failing to register any channels into the dmaengine framework?


[Severity: Critical]
This is a pre-existing issue, but does this misconfigure the DMA engine?

drivers/dma/fsl_raid.c:fsl_re_chan_probe() {
    ...
	out_be32(&chan->jrregs->inbring_base_h,
		 chan->inb_phys_addr & FSL_RE_ADDR_BIT_MASK);
	out_be32(&chan->jrregs->oubring_base_h,
		 chan->oub_phys_addr & FSL_RE_ADDR_BIT_MASK);
	out_be32(&chan->jrregs->inbring_base_l,
		 chan->inb_phys_addr >> FSL_RE_ADDR_BIT_SHIFT);
	out_be32(&chan->jrregs->oubring_base_l,
		 chan->oub_phys_addr >> FSL_RE_ADDR_BIT_SHIFT);
    ...
}

It appears the lower 32 bits are written into the high address register and
the upper 32 bits into the low address register. Can this result in invalid
physical memory accesses by the hardware, leading to silent memory corruption
or IOMMU faults?

[ ... ]

> @@ -738,7 +736,12 @@ static int fsl_re_chan_probe(struct platform_device *ofdev,
>  err_free_1:
>  	dma_pool_free(chan->re_dev->hw_desc_pool, chan->inb_ring_virt_addr,
>  		      chan->inb_phys_addr);
> +err_free_irq:
> +	free_irq(chan->irq, chan);
> +err_free_tasklet:
> +	tasklet_kill(&chan->irqtask);
>  err_free:
> +	of_platform_device_destroy(chandev, NULL);
>  	return ret;
>  }

[Severity: High]
The patch added free_irq() and tasklet_kill() after freeing the DMA memory in
err_free_1.

If an interrupt fires during this window, could the handler schedule the
tasklet which then accesses the freed or unallocated DMA rings? Does this
incorrect error unwind order create a use-after-free race condition?

[ ... ]

> @@ -844,6 +847,8 @@ static int fsl_re_probe(struct platform_device *ofdev)
>  
>  static void fsl_re_remove_chan(struct fsl_re_chan *chan)
>  {
> +	free_irq(chan->irq, chan);
> +

[Severity: High]
This is a pre-existing issue, but if fsl_re_chan_probe() fails early in its
execution, re_priv->re_jrs[q] is left as NULL.

Because total_chans is unconditionally incremented on early error in
fsl_re_probe():

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

Will this dereference the channel pointer without checking if it is NULL,
causing an immediate kernel crash?


[Severity: Critical]
This is a pre-existing issue, but if the device tree has multiple job queues
and a subsequent one fails validation:

drivers/dma/fsl_raid.c:fsl_re_probe() {
    ...
		rc = of_property_read_u32(np, "reg", &off);
		if (rc) {
			dev_err(dev, "Reg property not found in JQ node\n");
			return -ENODEV;
		}
    ...
}

Returning an error here abandons previously successful channels without tearing
down their active resources. Because re_priv is managed by devres, it will be
freed, leaving the active IRQ handler pointing to freed memory. Can this lead
to a resource leak and use-after-free memory corruption if an interrupt fires?


[Severity: High]
This is a pre-existing issue, but is there a potential deadlock in the DMA
callback execution?

The spinlock is acquired to protect the descriptor queues:

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

Then the client callback is invoked synchronously without dropping the spinlock
first:

drivers/dma/fsl_raid.c:fsl_re_desc_done() {
    ...
	dmaengine_desc_get_callback_invoke(&desc->async_tx, NULL);
    ...
}

Could this lead to an ABBA deadlock if the client attempts to allocate or
submit a new descriptor from its completion callback?


[Severity: High]
This is a pre-existing issue, but are the underlying channel resources (IRQs,
tasklets, DMA pools) completely destroyed here:

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]);
    ...
}

Before the framework unregistration occurs?

drivers/dma/fsl_raid.c:fsl_re_remove() {
    ...
	dma_async_device_unregister(&re_priv->dma_dev);
}

Does this leave a window for active clients to use freed resources if the
driver is unloaded or unbound while a concurrent DMA client is still active?

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

      reply	other threads:[~2026-09-10 20:30 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-10 20:15 [PATCHv3] dmaengine: fsl_raid: free resources in probe Rosen Penev
2026-09-10 20:30 ` sashiko-bot [this message]

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=20260910203007.F22801F000FF@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