Linux CAN drivers development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Zihan Xi" <zihanx@nebusec.ai>, linux-can@vger.kernel.org
Cc: "Marc Kleine-Budde" <mkl@pengutronix.de>,
	"Oliver Hartkopp" <socketcan@hartkopp.net>,
	"Vincent Mailhol" <mailhol@kernel.org>,
	"Oleksij Rempel" <o.rempel@pengutronix.de>
Subject: Re: [PATCH net v5 2/3] can: j1939: cancel TX timer after RX timeout
Date: Tue, 03 Nov 2026 05:54:09 +0000	[thread overview]
Message-ID: <sashiko-outbox-194600@kernel.org> (raw)
In-Reply-To: <02b6632da2b01b51edbe4c7b794ca3c473bfd559.1793681851.git.zihanx@nebusec.ai>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Critical] can: j1939: race in j1939_session_txtimer_cancel_async_locked() drops kref
--

commit 6ad432b9ff1c3b364014147532b4d663b71e57c7
Author: Zihan Xi <zihanx@nebusec.ai>

can: j1939: cancel TX timer after RX timeout

This commit cancels a J1939 session's TX timer asynchronously via
j1939_session_txtimer_cancel_async() when an RX timeout moves an active
session to J1939_SESSION_WAITING_ABORT in j1939_tp_rxtimer().

Link: https://bugtracker.nebusec.ai/f/11143

> diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
> index 4958f7c47ca44..c85d7bb3c12d4 100644
> --- a/net/can/j1939/transport.c
> +++ b/net/can/j1939/transport.c
> @@ -1387,6 +1387,7 @@ static enum hrtimer_restart j1939_tp_rxtimer(struct hrtimer *hrtimer)
>  						     struct j1939_session,
>  						     rxtimer);
>  	struct j1939_priv *priv = session->priv;
> +	bool cancelled = false;
>  
>  	if (session->state == J1939_SESSION_WAITING_ABORT) {
>  		netdev_alert(priv->ndev, "%s: 0x%p: abort rx timeout. Force session deactivation\n",
> @@ -1414,8 +1415,11 @@ static enum hrtimer_restart j1939_tp_rxtimer(struct hrtimer *hrtimer)
>  				      ms_to_ktime(J1939_XTP_ABORT_TIMEOUT_MS),
>  				      HRTIMER_MODE_REL_SOFT);
>  			__j1939_session_cancel(session, J1939_XTP_ABORT_TIMEOUT);
> +			cancelled = true;
>  		}
>  		j1939_session_list_unlock(session->priv);
> +		if (cancelled)
> +			j1939_session_txtimer_cancel_async(session);

[Severity: Critical]
Can calling j1939_session_txtimer_cancel_async() here race with a concurrent
j1939_session_txtimer_cancel() and re-arm session->txtimer without holding a
session kref, leading to a use-after-free of struct j1939_session?

Specifically, j1939_session_txtimer_cancel_async() calls
j1939_session_txtimer_cancel_async_locked():

net/can/j1939/transport.c:j1939_session_txtimer_cancel_async_locked() {
	lockdep_assert_held(&session->txtimer_lock);
	session->txtimer_shutdown = true;
	ret = hrtimer_try_to_cancel(&session->txtimer);
	/* Let a queued successor finish promptly after callback exit. */
	if (ret < 0 && session->txtimer_ref &&
	    hrtimer_is_queued(&session->txtimer))
		hrtimer_start(&session->txtimer, 0, HRTIMER_MODE_REL_SOFT);
	...
}

While j1939_session_txtimer_cancel() waits for a running callback outside
session->txtimer_lock:

net/can/j1939/transport.c:j1939_session_txtimer_cancel() {
	...
	/* Never wait for a softirq callback while holding txtimer_lock. */
	if (ret < 0) {
		ret = hrtimer_cancel(&session->txtimer);
		if (ret == 1) {
			spin_lock_bh(&session->txtimer_lock);
			if (!WARN_ON_ONCE(!session->txtimer_ref)) {
				session->txtimer_ref = false;
				put_ref = true;
			}
			spin_unlock_bh(&session->txtimer_lock);
		}
	}
	...
}

Consider the following sequence across three CPUs when an RX timeout occurs
while j1939_tp_txtimer() is completing and a synchronous cancellation (for
example via j1939_xtp_rx_abort_one() on the abort frame sent by
__j1939_session_cancel(), or via an incoming CTS/RTS frame) runs
concurrently:

1. On CPU 0, j1939_tp_txtimer() is running, has queued a successor via
   j1939_tp_schedule_txtimer() (so session->txtimer is queued and
   session->txtimer_ref is true), releases session->txtimer_lock, and is
   about to finish __run_hrtimer().

2. On CPU 1, j1939_session_txtimer_cancel() increments
   session->txtimer_cancelers, sees hrtimer_try_to_cancel() return -1 because
   CPU 0 has not cleared base->running yet, drops session->txtimer_lock, and
   calls hrtimer_cancel(&session->txtimer).

3. On CPU 2, j1939_tp_rxtimer() calls j1939_session_txtimer_cancel_async(),
   which acquires session->txtimer_lock and enters
   j1939_session_txtimer_cancel_async_locked(). It also sees
   hrtimer_try_to_cancel() return -1 while CPU 0 is still in __run_hrtimer(),
   and evaluates ret < 0 && session->txtimer_ref &&
   hrtimer_is_queued(&session->txtimer) as true without checking
   session->txtimer_cancelers.

4. CPU 0 finishes __run_hrtimer() and clears base->running. On CPU 1,
   hrtimer_cancel(&session->txtimer) immediately succeeds in cancelling the
   queued timer and returns 1.

5. CPU 2 calls hrtimer_start(&session->txtimer, 0, HRTIMER_MODE_REL_SOFT),
   re-enqueuing session->txtimer, and releases session->txtimer_lock.

6. CPU 1 acquires session->txtimer_lock, sees ret == 1 and
   session->txtimer_ref == true, sets session->txtimer_ref = false, and drops
   the timer's session reference via j1939_session_put(session).

At that point, session->txtimer is queued in the hrtimer subsystem with
session->txtimer_ref == false and no kref pinning the session. Should
j1939_session_txtimer_cancel_async_locked() avoid calling hrtimer_start()
when session->txtimer_cancelers is non-zero (or otherwise synchronize with
concurrent cancelers)?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1793681851.git.zihanx@nebusec.ai?part=2

  reply	other threads:[~2026-11-03  5:54 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-03  5:24 [PATCH net v5 0/3] can: j1939: fix TX timer reference leak Zihan Xi
2026-11-03  5:24 ` [PATCH net v5 1/3] can: j1939: fix TX timer reference accounting Zihan Xi
2026-11-03  5:48   ` sashiko-bot
2026-11-04 18:38   ` netdev-bot+sashiko
2026-11-03  5:24 ` [PATCH net v5 2/3] can: j1939: cancel TX timer after RX timeout Zihan Xi
2026-11-03  5:54   ` sashiko-bot [this message]
2026-11-04 18:38   ` netdev-bot+sashiko
2026-11-03  5:24 ` [PATCH net v5 3/3] can: j1939: serialize session TX with state changes Zihan Xi
2026-11-03  5:46   ` sashiko-bot
2026-11-04 18:38   ` netdev-bot+sashiko

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=sashiko-outbox-194600@kernel.org \
    --to=sashiko-bot@kernel.org \
    --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=zihanx@nebusec.ai \
    /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