From: sashiko-bot@kernel.org
To: "Chaosheng Qu" <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 v7 1/4] can: j1939: arm the abort timer under the session list lock
Date: Wed, 11 Nov 2026 06:45:01 +0000 [thread overview]
Message-ID: <sashiko-outbox-208458@kernel.org> (raw)
In-Reply-To: <179410166345.60581.16722127854597502548@163.com>
Thank you for your contribution! Sashiko AI review found 3 potential
issues to consider:
- [High] can: j1939: race in j1939_session_cancel() double-arms rxtimer
and leaks session
- [Medium] can: j1939: j1939_session_cancel() leaves rxtimer armed on
deactivated session
- [Low] can: j1939: missing Fixes trailer for commit d966635b384b
--
commit d2f1f6071a930db192083744d44435260ec61c4f
Author: Chaosheng Qu <quchaosheng000406@163.com>
> can: j1939: arm the abort timer under the session list lock
>
> j1939_session_cancel() cancels the receive timer while holding
> active_session_list_lock. hrtimer_cancel() waits for a callback that is
> already running, and j1939_tp_rxtimer() takes the same lock, so a softirq
> callback waiting for the lock deadlocks against the CPU that holds it.
> Cancel the timer before taking the lock instead.
>
> Cancelling outside the lock opens a second window: the cancel/get/start
> sequence is no longer atomic against j1939_tp_set_rxtimeout(), which rearms
> the same timer from the receive path without holding the lock. A
> concurrent
> arm in that window queues a timer whose reference is never dropped, and the
> session then never reaches j1939_session_destroy(), keeping both its netdev
> and its j1939_priv reference alive. Take the lock for the rearms so both
> armers are serialized; hrtimer_start() does not wait for a callback, so it
> is safe to call while holding it.
>
> A session that is already in J1939_SESSION_WAITING_ABORT also gets its
> timer
> back. A second unparsable frame re-enters j1939_session_cancel() after
> j1939_session_timers_cancel() has killed the timer, and without a rearmed
> timer nothing ever moves that session out of WAITING_ABORT, so
> unregistering
> the device hangs in unregister_netdevice().
>
> The reference accounting stays balanced: one j1939_session_get() per
> hrtimer_start(), dropped by j1939_session_put() in j1939_tp_rxtimer() when
> the timer fires.
>
> Signed-off-by: Chaosheng Qu <quchaosheng000406@163.com>
[Severity: Low]
This fixes the locking and timer re-arming in j1939_session_cancel().
Should this include:
Fixes: d966635b384b ("can: j1939: transport: make sure the aborted session will be deactivated only once")
> diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
> index 8fcfd13e5e6f8..590a04c453b56 100644
> --- a/net/can/j1939/transport.c
> +++ b/net/can/j1939/transport.c
> @@ -1161,12 +1161,38 @@ static void __j1939_session_cancel(struct j1939_session *session,
> static void j1939_session_cancel(struct j1939_session *session,
> enum j1939_xtp_abort err)
> {
> + bool abort_sent = false;
> +
> + /* Cancel the abort timer before taking the list lock.
> + *
> + * hrtimer_cancel() waits for a callback that is already running, and
> + * j1939_tp_rxtimer() takes the same lock, so cancelling the timer while
> + * holding active_session_list_lock can deadlock: the lock holder waits
> + * for the callback, the callback waits for the lock.
> + */
> + j1939_session_rxtimer_cancel(session);
> +
> j1939_session_list_lock(session->priv);
>
> 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);
> + abort_sent = true;
> }
> +
> + /* Re-arm under the lock, whether the abort frame just went out or the
> + * session is already in WAITING_ABORT and only needs its timer back.
> + *
> + * hrtimer_start() does not wait for a running callback, so arming here
> + * cannot deadlock, and taking the lock closes the window against
> + * j1939_tp_set_rxtimeout(), which rearms the same timer from the
> + * receive path without holding it.
> + */
[Severity: High]
Can a concurrent timer arm between j1939_session_rxtimer_cancel() and
hrtimer_start() leak a session reference?
j1939_tp_set_rxtimeout() does not acquire active_session_list_lock, so
taking the lock here does not serialize the two paths. Even between two
concurrent j1939_session_cancel() callers (for example from
j1939_tp_txtimer() and j1939_tp_recv()), both cancel rxtimer before taking
the lock:
CPU0 CPU1
j1939_session_cancel()
j1939_session_rxtimer_cancel()
j1939_session_cancel()
j1939_session_rxtimer_cancel()
j1939_session_list_lock()
session->state = ..._WAITING_ABORT
j1939_session_get(session)
hrtimer_start(&session->rxtimer)
j1939_session_list_unlock()
j1939_session_list_lock()
/* state == WAITING_ABORT */
j1939_session_get(session)
hrtimer_start(&session->rxtimer)
<-- re-queues armed timer, leaks ref
Calling hrtimer_start() on an already-queued rxtimer replaces it in place
without dropping the previous reference, so session->kref never reaches zero
and unregister_netdevice() hangs waiting for the leaked netdev reference.
> + if (abort_sent || session->state == J1939_SESSION_WAITING_ABORT) {
> + j1939_session_get(session);
> + hrtimer_start(&session->rxtimer,
> + ms_to_ktime(J1939_XTP_ABORT_TIMEOUT_MS),
> + HRTIMER_MODE_REL_SOFT);
> + }
[Severity: Medium]
Does re-arming session->rxtimer when session->state is already
J1939_SESSION_WAITING_ABORT leave rxtimer running on a deactivated session in
j1939_xtp_rx_rts_session_active()?
When a duplicate RTS frame arrives on an active session with
session->last_cmd != 0, j1939_xtp_rx_rts_session_active() cancels and
immediately deactivates the session:
net/can/j1939/transport.c:j1939_xtp_rx_rts_session_active() {
...
j1939_session_timers_cancel(session);
j1939_session_cancel(session, J1939_XTP_ABORT_BUSY);
if (session->transmission) {
j1939_session_deactivate_activate_next(session);
} else if (session->state == J1939_SESSION_WAITING_ABORT) {
...
j1939_session_deactivate_activate_next(session);
}
}
With this change, j1939_session_cancel() re-arms rxtimer, and
j1939_session_deactivate_activate_next() then sets session->state to
J1939_SESSION_DONE and removes the session from priv->active_session_list
without cancelling rxtimer. When rxtimer fires 500ms later on the
J1939_SESSION_DONE session, j1939_tp_rxtimer() takes the else branch and
sends a duplicate J1939_ERRQUEUE_RX_ABORT notification.
--
Sashiko AI review · https://sashiko.dev/#/patchset/179410166344.60581.3898011861151549156@163.com?part=1
next prev parent reply other threads:[~2026-11-11 6:45 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-08 1:34 [PATCH net v7 0/4] can: j1939: fix the abort timer and bound EDPO Chaosheng Qu
2026-11-08 1:34 ` [PATCH net v7 3/4] can: j1939: drop the message when the reassembled skb is gone Chaosheng Qu
2026-11-12 21:49 ` netdev-bot+sashiko
2026-11-13 3:11 ` Chaosheng Qu
2026-11-08 1:34 ` [PATCH net v7 4/4] can: j1939: reject a CTS that names more packets than the message has Chaosheng Qu
2026-11-12 21:49 ` netdev-bot+sashiko
2026-11-13 3:11 ` Chaosheng Qu
2026-11-08 1:34 ` [PATCH net v7 1/4] can: j1939: arm the abort timer under the session list lock Chaosheng Qu
2026-11-11 6:45 ` sashiko-bot [this message]
2026-11-12 21:49 ` netdev-bot+sashiko
2026-11-13 3:11 ` Chaosheng Qu
2026-11-08 1:34 ` [PATCH net v7 2/4] can: j1939: validate the EDPO packet number Chaosheng Qu
2026-11-11 7:04 ` sashiko-bot
2026-11-12 21:49 ` netdev-bot+sashiko
2026-11-13 3:11 ` 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-208458@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 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.