Linux CAN drivers development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: Biju <biju.das.au@gmail.com>
Cc: "Oliver Hartkopp" <socketcan@hartkopp.net>,
	"Marc Kleine-Budde" <mkl@pengutronix.de>,
	"Vincent Mailhol" <mailhol@kernel.org>,
	wsa+renesas@sang-engineering.com,
	"Oleksij Rempel" <o.rempel@pengutronix.de>,
	linux-can@vger.kernel.org
Subject: Re: [PATCH 2/3] can: rcar_canfd: Fix double-cleanup and unclocked register access on init failure
Date: Tue, 30 Jun 2026 14:06:28 +0000	[thread overview]
Message-ID: <20260630140629.5065C1F00A3A@smtp.kernel.org> (raw)
In-Reply-To: <20260630135119.104774-3-biju.das.jz@bp.renesas.com>

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

New issues:
- [High] Use-after-free read on the error path of rcar_canfd_channel_probe().
- [High] The CAN network device is registered and exposed to userspace before its global and shared interrupts are requested, introducing a race condition.

Pre-existing issues:
- [High] Use-After-Free vulnerability in error and removal paths due to mismatched devm-managed interrupt lifetimes and dangling pointers.
- [High] Incorrect clearing of W0C (Write-0-To-Clear) hardware status registers can silently drop concurrent interrupts.
--

commit a601711f6b0c8a2b4d0262288f6d110cc98b8332
Author: Biju Das <biju.das.jz@bp.renesas.com>

can: rcar_canfd: Fix double-cleanup and unclocked register access on init failure

In rcar_canfd_probe(), if rcar_canfd_global_init() encounters an error,
it disables the clocks and asserts the resets before returning. However,
the probe function then jumps to the fail_mode label and unconditionally
calls rcar_canfd_global_deinit(), which writes to hardware registers and
causes a synchronous external abort. This commit makes the failure path
jump directly to fail_dev, skipping the redundant global_deinit() call.

> diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
> index 5aafbab85da67..1f3dc4b354f87 100644
> --- a/drivers/net/can/rcar/rcar_canfd.c
> +++ b/drivers/net/can/rcar/rcar_canfd.c
> @@ -2257,7 +2257,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
>  
>  	err = rcar_canfd_global_init(gpriv);
>  	if (err)
> -		goto fail_mode;
> +		goto fail_dev;
>  
>  	for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) {

[Severity: High]
Could this code expose the network interface to userspace before its interrupts
are fully set up?

The loop registers the channels via rcar_canfd_channel_probe(), which calls
register_candev(). However, the shared global interrupts (ch_irq, g_irq) are
not requested via devm_request_irq() until after the channel loop completes.

If a userspace process (e.g., systemd-networkd) brings the interface UP
immediately upon registration, could rcar_canfd_open() start the hardware and
enable interrupts before the OS has registered the IRQ handlers, leading to
unhandled interrupts?

>  		err = rcar_canfd_channel_probe(gpriv, ch, fcan_freq,
>  					       transceivers[ch]);
[ ... ]
> @@ -2275,7 +2275,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
>  fail_channel:
>  	for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels)
>  		rcar_canfd_channel_remove(gpriv, ch);

[Severity: High]
This is a pre-existing issue, but is there a use-after-free vulnerability
here due to mismatched interrupt lifetimes?

When rcar_canfd_channel_remove() frees the network device and its inline
private data priv via free_candev(priv->ndev), the devm_request_irq()
shared interrupt handlers remain active until devres cleanup runs after
probe() or remove() returns.

If a shared interrupt fires during this window, wouldn't the handler
(e.g., rcar_canfd_global_interrupt()) execute and unconditionally
dereference gpriv->ch[ch]->base, accessing the freed priv memory?

> -fail_mode:
> +
>  	rcar_canfd_global_deinit(gpriv, false);
>  fail_dev:
>  	return err;


I also noticed a few other issues in this file:

[Severity: High]
This is a pre-existing issue, but won't the driver incorrectly clear
W0C (Write-0-To-Clear) hardware status registers?

In functions like rcar_canfd_tx_done(), rcar_canfd_rx_poll(), and
rcar_canfd_global_error(), the driver reads the status register into sts
and writes back sts & ~FLAG:

drivers/net/can/rcar/rcar_canfd.c:rcar_canfd_tx_done() {
    ...
    rcar_canfd_write(priv->base, RCANFD_CFSTS(gpriv, ch, RCANFD_CFFIFO_IDX),
                     sts & ~RCANFD_CFSTS_CFTXIF);
    ...
}

Because this bitwise operation leaves 0s in bit positions that were
originally 0, won't writing 0 inadvertently clear any flag that was
asserted by the hardware after the register was initially read, leading to
silent loss of hardware interrupts and dropped packets?


[Severity: High]
Is there a use-after-free read in the error path of rcar_canfd_channel_probe()?

When device registration fails, the error path calls free_candev(ndev)
which frees the net_device and its inline private data priv:

drivers/net/can/rcar/rcar_canfd.c:rcar_canfd_channel_probe() {
    ...
fail:
	free_candev(ndev);
	gpriv->ch[priv->channel] = NULL;
	return err;
}

Immediately following the free, the code attempts to nullify the global
pointer array using priv->channel. Since priv has already been freed,
isn't this a use-after-free read?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260630135119.104774-1-biju.das.jz@bp.renesas.com?part=2

  reply	other threads:[~2026-06-30 14:06 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-30 13:51 [PATCH 0/3] Renesas CANFD Fixes Biju
2026-06-30 13:51 ` [PATCH 1/3] can: rcar_canfd: Fix dangling pointer on channel probe failure Biju
2026-06-30 13:59   ` sashiko-bot
2026-06-30 13:51 ` [PATCH 2/3] can: rcar_canfd: Fix double-cleanup and unclocked register access on init failure Biju
2026-06-30 14:06   ` sashiko-bot [this message]
2026-06-30 13:51 ` [PATCH 3/3] can: rcar_canfd: Fix interrupt registration order Biju
2026-06-30 14:05   ` sashiko-bot

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=20260630140629.5065C1F00A3A@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=biju.das.au@gmail.com \
    --cc=linux-can@vger.kernel.org \
    --cc=mailhol@kernel.org \
    --cc=mkl@pengutronix.de \
    --cc=o.rempel@pengutronix.de \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=socketcan@hartkopp.net \
    --cc=wsa+renesas@sang-engineering.com \
    /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