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, vkoul@kernel.org, dmaengine@vger.kernel.org
Subject: Re: [PATCHv4] dmaengine: fsl_raid: check fsl_re_chan_probe() return value
Date: Thu, 10 Sep 2026 20:18:05 +0000	[thread overview]
Message-ID: <20260910201806.0D6601F000FF@smtp.kernel.org> (raw)
In-Reply-To: <20260910200637.41512-1-rosenp@gmail.com>

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

Pre-existing issues:
- [High] The driver never frees requested IRQs or unregisters child platform devices, causing resource leaks and use-after-free on error paths and driver unbind.
- [High] Returning an error from `dma_async_device_register()` or early returns in `fsl_re_probe()` fail to unwind successfully probed channels, causing resource leaks and UAF.
- [High] DMA channels are never added to the DMA device channels list, rendering the driver non-functional.
- [High] Interrupt is requested before private data and hardware are fully initialized, risking a NULL pointer dereference in the interrupt handler.
- [High] Channel resources are destroyed before the DMA device is unregistered, allowing concurrent use-after-free.
--

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

dmaengine: fsl_raid: check fsl_re_chan_probe() return value

The commit fixes a potential NULL pointer dereference in fsl_re_remove_chan()
by checking the return value of fsl_re_chan_probe() during device probe and
guarding against NULL entries during removal.

> diff --git a/drivers/dma/fsl_raid.c b/drivers/dma/fsl_raid.c
> index 2d86f61105e52..66b7ff0f31f70 100644
> --- a/drivers/dma/fsl_raid.c
> +++ b/drivers/dma/fsl_raid.c
> @@ -828,18 +828,32 @@ static int fsl_re_probe(struct platform_device *ofdev)
>  		}
>  		/* Find out the Job Rings present under each JQ */
>  		for_each_child_of_node(np, child) {
> +			if (ridx >= FSL_RE_MAX_CHANS) {
> +				dev_warn(dev,
> +					"too many job rings, max %d\n",
> +					FSL_RE_MAX_CHANS);
> +				of_node_put(child);
> +				break;
> +			}
> +
>  			rc = of_device_is_compatible(child,
>  					     "fsl,raideng-v1.0-job-ring");
> +			if (!rc)
> +				continue;
> +
>  			rc = fsl_re_chan_probe(ofdev, child, ridx, off);

[Severity: High]
This is a pre-existing issue, but does fsl_re_chan_probe() leak resources on
failure and driver unbind?

In fsl_re_chan_probe(), a platform device is created and an interrupt is
requested without devres management:

    chan_ofdev = of_platform_device_create(np, NULL, dev);
    ...
    ret = request_irq(chan->irq, fsl_re_isr, 0, chan->name, chandev);

The error path just returns without unwinding these:

err_free:
    return ret;

Furthermore, fsl_re_remove_chan() destroys the tasklet but does not free the
interrupt or unregister the child device. Since devres will automatically free
the chan structure on unbind, wouldn't the leaked active interrupt cause a
use-after-free if it fires and accesses the freed chan structure?

[Severity: High]
This is another pre-existing issue, but are the channels ever linked to the
device's channels list?

fsl_re_chan_probe() sets the device pointer:

    chan->chan.device = dma_dev;
    chan->chan.private = chan;

However, it seems to miss linking the channel into the parent device's
channel list. When dma_async_device_register() is called later, wouldn't it
see an empty channels list and register zero channels, rendering the driver
non-functional?

[Severity: High]
This is a pre-existing issue, but is there a race condition between requesting
the interrupt and setting the driver data?

fsl_re_chan_probe() requests the interrupt before setting the driver data:

    ret = request_irq(chan->irq, fsl_re_isr, 0, chan->name, chandev);
    ...
    dev_set_drvdata(chandev, chan);

If the interrupt fires in this window, fsl_re_isr() will read a NULL pointer
from dev_get_drvdata() and unconditionally dereference it:

    re_chan = dev_get_drvdata((struct device *)data);
    irqstate = in_be32(&re_chan->jrregs->jr_interrupt_status);

Can this lead to a NULL pointer dereference panic?

>  			if (rc) {
> -				fsl_re_chan_probe(ofdev, child, ridx++, off);
> -				re_priv->total_chans++;
> +				dev_err(dev,
> +					"job ring %d probe failed: %d\n",
> +					ridx, rc);
> +				continue;
>  			}
> +			ridx++;
> +			re_priv->total_chans++;
>  		}
>  	}
>  
> -	dma_async_device_register(dma_dev);
> -
> -	return 0;
> +	return dma_async_device_register(dma_dev);

[Severity: High]
This is a pre-existing issue, but if dma_async_device_register() fails, are
the successfully probed channels abandoned?

When dma_async_device_register() returns an error, the function exits without
calling fsl_re_remove() to clean up any channels initialized during earlier
job queue iterations.

Since the interrupts for these channels are not devres-managed, they would
remain active. Once devres frees the associated chan memory, could an
interrupt firing trigger a use-after-free crash?

>  }
>  
>  static void fsl_re_remove_chan(struct fsl_re_chan *chan)
> @@ -864,7 +878,8 @@ static void fsl_re_remove(struct platform_device *ofdev)
>  
>  	/* Cleanup chan related memory areas */
>  	for (i = 0; i < re_priv->total_chans; i++)
> -		fsl_re_remove_chan(re_priv->re_jrs[i]);
> +		if (re_priv->re_jrs[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 are channel resources destroyed prematurely
during driver unbind?

fsl_re_remove_chan() is called for each channel, killing tasklets and freeing
dma pools:

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

Afterward, the device is unregistered:

    dma_async_device_unregister(&re_priv->dma_dev);

Since the subsystem still considers the device active until unregistration
completes, could concurrent or pending requests attempt to use the already
freed pools or schedule the killed tasklets?

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

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

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-10 20:06 [PATCHv4] dmaengine: fsl_raid: check fsl_re_chan_probe() return value Rosen Penev
2026-09-10 20:18 ` sashiko-bot [this message]
2026-09-11 15:21 ` Frank Li

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=20260910201806.0D6601F000FF@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.