Linux CAN drivers development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: Quchaosheng <quchaosheng000406@163.com>
Cc: linux-can@vger.kernel.org,
	"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 v6 1/1] can: j1939: validate the EDPO packet number
Date: Thu, 22 Oct 2026 08:03:34 +0000	[thread overview]
Message-ID: <sashiko-outbox-181151@kernel.org> (raw)
In-Reply-To: <179265494813.314254.14725785769836234084@163.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] can: j1939: race on rxtimer and state in j1939_session_cancel()
--

commit c1bc44e269c86cae99ab16d5fb0f92e924343f7e
Author: Quchaosheng <quchaosheng000406@163.com>

can: j1939: validate the EDPO packet number

This commit validates the peer-controlled packet offset in ETP.CM_DPO frames
against session->pkt.total and adds a NULL skb check in
j1939_session_completed(). It also updates j1939_session_cancel() to cancel
rxtimer before taking active_session_list_lock and to deactivate sessions
already in J1939_SESSION_WAITING_ABORT.

Link: https://sashiko.dev/#/patchset/20260928193312.553632-1-mkl@pengutronix.de?part=3

> diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
> index 8fcfd13e5e6f8..2cc6c46c4d50b 100644
> --- a/net/can/j1939/transport.c
> +++ b/net/can/j1939/transport.c
> @@ -1161,18 +1161,39 @@ static void __j1939_session_cancel(struct j1939_session *session,
>  static void j1939_session_cancel(struct j1939_session *session,
>  				 enum j1939_xtp_abort err)
>  {
> +	bool waiting;
> +
> +	/* Cancel the rxtimer before taking the list lock: hrtimer_cancel()
> +	 * waits for a running callback, and j1939_tp_rxtimer() takes the
> +	 * same lock.
> +	 */
> +	j1939_session_rxtimer_cancel(session);
>  	j1939_session_list_lock(session->priv);
>  
> +	waiting = session->state == J1939_SESSION_WAITING_ABORT;
>  	if (session->state >= J1939_SESSION_ACTIVE &&
>  	    session->state < J1939_SESSION_WAITING_ABORT) {
> -		j1939_tp_set_rxtimeout(session, J1939_XTP_ABORT_TIMEOUT_MS);
>  		__j1939_session_cancel(session, err);
> +		/* hrtimer_start() does not wait for the callback, so arming
> +		 * the abort timer here cannot deadlock.
> +		 */
> +		j1939_session_get(session);
> +		hrtimer_start(&session->rxtimer,
> +			      ms_to_ktime(J1939_XTP_ABORT_TIMEOUT_MS),
> +			      HRTIMER_MODE_REL_SOFT);
>  	}
>  
>  	j1939_session_list_unlock(session->priv);
>  
>  	if (!session->sk)
>  		j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT);
> +
> +	/* The abort went out on an earlier call, and this caller has just
> +	 * cancelled the timer that would have finished the session off, so
> +	 * nothing else is left to deactivate it.
> +	 */
> +	if (waiting)
> +		j1939_session_deactivate_activate_next(session);
>  }

[Severity: High]
In j1939_session_cancel(), j1939_session_rxtimer_cancel(session) is called
before acquiring active_session_list_lock, while session->rxtimer is re-armed
and waiting is evaluated under that lock.

Can this window between cancelling session->rxtimer and acquiring
active_session_list_lock introduce two races with concurrent receive packet
processing or a concurrent j1939_session_cancel() call?

First, receive handlers such as j1939_xtp_rx_dat_one(),
j1939_xtp_rx_cts_one(), and j1939_xtp_rx_dpo_one() call
j1939_tp_set_rxtimeout(session, ...) without holding active_session_list_lock.
If another processor calls j1939_tp_set_rxtimeout() after
j1939_session_rxtimer_cancel() returns here, but before
active_session_list_lock is acquired:

  j1939_session_cancel()
    j1939_session_rxtimer_cancel(session);
                                         j1939_tp_set_rxtimeout()
                                           j1939_session_rxtimer_cancel(session);
                                           j1939_session_get(session);
                                           hrtimer_start(&session->rxtimer, ...);
    j1939_session_list_lock(session->priv);
    __j1939_session_cancel(session, err);
    j1939_session_get(session);
    hrtimer_start(&session->rxtimer, ...);

Doesn't hrtimer_start() in j1939_session_cancel() re-enqueue session->rxtimer
while it is already armed, overwriting it without dropping the reference
taken by j1939_tp_set_rxtimeout() and permanently leaking session->kref
(which also holds a netdev reference on priv->ndev and blocks
unregister_netdevice())?

Second, if two callers concurrently enter j1939_session_cancel() on the same
session (for example, j1939_tp_txtimer() racing with an incoming packet),
both can execute j1939_session_rxtimer_cancel(session) before either acquires
active_session_list_lock:

  j1939_session_cancel()                 j1939_session_cancel()
    j1939_session_rxtimer_cancel()         j1939_session_rxtimer_cancel()
    j1939_session_list_lock()
    __j1939_session_cancel()
      session->state = J1939_SESSION_WAITING_ABORT;
    j1939_session_get(session);
    hrtimer_start(&session->rxtimer, ...);
    j1939_session_list_unlock()
                                           j1939_session_list_lock()
                                           waiting = session->state ==
                                             J1939_SESSION_WAITING_ABORT;
                                           j1939_session_list_unlock()
                                           if (waiting)
                                             j1939_session_deactivate_activate_next()

Wouldn't the second caller observe waiting as true and call
j1939_session_deactivate_activate_next(session) even though its
j1939_session_rxtimer_cancel() ran before the first caller armed the abort
timer, removing the session from priv->active_session_list while
session->rxtimer remains armed?

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/179265494813.314254.14725785769836234084@163.com?part=1

  reply	other threads:[~2026-10-22  8:03 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-22  7:42 [PATCH net v6 1/1] can: j1939: validate the EDPO packet number Quchaosheng
2026-10-22  8:03 ` sashiko-bot [this message]
2026-10-23 20:51 ` netdev-bot+sashiko
2026-10-25  2:18   ` Chaosheng Qu

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-181151@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=quchaosheng000406@163.com \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=socketcan@hartkopp.net \
    /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