All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Rosen Penev" <rosenp@gmail.com>
Cc: Frank.Li@kernel.org, dmaengine@vger.kernel.org, vkoul@kernel.org
Subject: Re: [PATCH] dmaengine: fsl_raid: free resources in probe
Date: Sat, 18 Jul 2026 23:28:18 +0000	[thread overview]
Message-ID: <20260718232819.04ECF1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260718231716.230144-1-rosenp@gmail.com>

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

New issues:
- [High] Improper Device Cleanup / List Corruption
- [High] Race Condition / Teardown Order resulting in Use-After-Free
- [High] Double-Free / NULL Pointer Dereference due to Ignored Probe Error

Pre-existing issues:
- [High] Race Condition / Uninitialized Data in ISR
- [High] Resource Leak and Kernel Panic on JQ Node Parse Failure
- [High] Concurrency / Use-After-Free during DMA Unregistration
- [High] Buffer Overflow / Out-of-Bounds Write from Device Tree
--

--- Patch [1]: [PATCH] dmaengine: fsl_raid: free resources in probe ---
commit 6b03aff77ef1f481579072d2caa275fbf35f0665
Author: Rosen Penev <rosenp@gmail.com>

dmaengine: fsl_raid: free resources in probe

This patch adds resource cleanup in the error unwind path of
fsl_re_chan_probe and in fsl_re_remove_chan. It adds free_irq, tasklet_kill,
and platform_device_put, while switching to platform_get/set_drvdata.

> diff --git a/drivers/dma/fsl_raid.c b/drivers/dma/fsl_raid.c
> index 99945845d8b5e..5f9c92c86593e 100644
> --- a/drivers/dma/fsl_raid.c
> +++ b/drivers/dma/fsl_raid.c

[ ... ]

> @@ -672,17 +672,18 @@ static int fsl_re_chan_probe(struct platform_device *ofdev,
>  	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_ofdev);

[Severity: High]
This isn't a bug introduced by this patch, but by requesting the IRQ here, is
there a window where the interrupt can fire before platform_set_drvdata() is
called later in this function?

If the ISR runs immediately, it will read a NULL pointer from
platform_get_drvdata() and dereference it when reading the interrupt status.

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

[ ... ]

> @@ -738,7 +739,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_ofdev);
> +err_free_tasklet:
> +	tasklet_kill(&chan->irqtask);
>  err_free:
> +	platform_device_put(chan_ofdev);

[Severity: High]
Does platform_device_put() correctly clean up the device created by
of_platform_device_create()?

Since of_platform_device_create() allocates and registers the device with
the system bus, the initial reference belongs to the device core. Does calling
platform_device_put() here drop a reference the driver doesn't own, leading
to a reference count underflow and a subsequent use-after-free?

Would of_platform_device_destroy() or platform_device_unregister() be the
correct teardown function to use instead?

[Severity: High]
If fsl_re_chan_probe() fails and executes these new destructors, does the
driver handle the failure correctly in fsl_re_probe()?

Looking at fsl_re_probe(), the return value of fsl_re_chan_probe() is ignored
and total_chans is incremented anyway:

fsl_re_probe() {
    ...
    for_each_child_of_node(np, child) {
        ...
        if (rc) {
            fsl_re_chan_probe(ofdev, child, ridx++, off);
            re_priv->total_chans++;
        }
    }
}

Since total_chans is still incremented, fsl_re_remove() will eventually
iterate over this failed channel and call fsl_re_remove_chan(). Does this
result in a double free of the IRQ and device, or a NULL pointer dereference
since the cleanup already happened in the probe error path?

>  	return ret;
>  }

[ ... ]

> @@ -819,7 +825,7 @@ static int fsl_re_probe(struct platform_device *ofdev)
>  		return -ENOMEM;
>  	}
>  
> -	dev_set_drvdata(dev, re_priv);
> +	platform_set_drvdata(ofdev, re_priv);

[Severity: High]
This isn't a bug introduced by this patch, but looking at fsl_re_probe(), is
there a risk of an out-of-bounds write if the device tree has too many child
nodes?

fsl_re_probe() {
    ...
    for_each_child_of_node(np, child) {
        ...
            fsl_re_chan_probe(ofdev, child, ridx++, off);
    }
}

fsl_re_chan_probe() uses this index to store the channel in re_jrs:
    re_priv->re_jrs[q] = chan;

Since re_jrs has a fixed size of 4, will this corrupt memory if more than 4 
job rings are defined in the device tree?

[Severity: High]
This is another pre-existing issue, but does fsl_re_probe() leak resources if
a secondary Job Queue node fails to parse?

fsl_re_probe() {
    ...
    for_each_compatible_node_scoped(np, NULL, "fsl,raideng-v1.0-job-queue") {
        rc = of_property_read_u32(np, "reg", &off);
        if (rc) {
            dev_err(dev, "Reg property not found in JQ node\n");
            return -ENODEV;
        }
        ...
}

If this early return is hit on a subsequent loop iteration, are the channels
probed in previous iterations leaked because fsl_re_remove() won't be called?

Could this also cause a kernel panic if an active IRQ fires and attempts to
access the unmapped re_regs since devres will clean up the mapped memory?

>  
>  	/* Parse Device tree to find out the total number of JQs present */
>  	for_each_compatible_node_scoped(np, NULL, "fsl,raideng-v1.0-job-queue") {

[ ... ]

> @@ -848,21 +854,23 @@ static void fsl_re_remove_chan(struct fsl_re_chan *chan)
>  {
>  	tasklet_kill(&chan->irqtask);
>  
> +	free_irq(chan->irq, chan->ofdev);

[Severity: High]
Is there a race condition here by calling free_irq() after tasklet_kill()?

If a hardware interrupt fires between tasklet_kill() and free_irq(), the ISR
will execute and re-schedule the tasklet. Will this result in a pending
tasklet running after the channel memory has been freed, causing a
use-after-free?

Should free_irq() be called first to ensure no new tasklets can be scheduled?

> +
>  	dma_pool_free(chan->re_dev->hw_desc_pool, chan->inb_ring_virt_addr,
>  		      chan->inb_phys_addr);
>  
>  	dma_pool_free(chan->re_dev->hw_desc_pool, chan->oub_ring_virt_addr,
>  		      chan->oub_phys_addr);
> +
> +	platform_device_put(chan->ofdev);

[Severity: High]
Similar to the probe error path, does platform_device_put() cause a reference
count underflow here?

Since the device was created with of_platform_device_create(), would
of_platform_device_destroy() or platform_device_unregister() be the correct
way to clean it up?

>  }
>  
>  static void fsl_re_remove(struct platform_device *ofdev)
>  {
>  	struct fsl_re_drv_private *re_priv;
> -	struct device *dev;
>  	int i;
>  
> -	dev = &ofdev->dev;
> -	re_priv = dev_get_drvdata(dev);
> +	re_priv = platform_get_drvdata(ofdev);
>  
>  	/* Cleanup chan related memory areas */
>  	for (i = 0; i < re_priv->total_chans; i++)

[Severity: High]
This is a pre-existing issue, but does fsl_re_remove() tear down the
channels in the wrong order relative to unregistering the DMA device?

fsl_re_remove() {
    ...
    for (i = 0; i < re_priv->total_chans; i++)
        fsl_re_remove_chan(re_priv->re_jrs[i]);

    dma_async_device_unregister(&re_priv->dma_dev);
}

Since dma_async_device_unregister() is called after destroying the channels,
is there a window where the DMA engine core might still issue new requests or
query channel status after the DMA pools and IRQs have been freed?

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

      reply	other threads:[~2026-07-18 23:28 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-18 23:17 [PATCH] dmaengine: fsl_raid: free resources in probe Rosen Penev
2026-07-18 23:28 ` 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=20260718232819.04ECF1F000E9@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.