Re: [PATCH v8] can: isotp: fix timer drain order, wakeup handling and tx_gen ordering

[email protected] Tue, 21 Jul 2026 14:54:19 +0000
Newsgroups org.kernel.vger.linux-can
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

New issues:
- [High] Missing acquire barrier in wait condition allows stale read of tx_result, spuriously failing transmissions.

Pre-existing issues:
- [High] Invalid Flow Control frames abort the transmission but falsely report success to the sender.
--

--- Patch [1]: [PATCH v8] can: isotp: fix timer drain order, wakeup handling and tx_gen ordering ---
commit 2db87f7eca662e755db3d9c7c9c258bea453c5f2
Author: Oliver Hartkopp <[email protected]>

can: isotp: fix timer drain order, wakeup handling and tx_gen ordering

This patch addresses multiple findings in the CAN ISOTP subsystem
regarding timer drain order, wakeup handling, concurrent transfer
generation tracking, and error reporting.

> diff --git a/net/can/isotp.c b/net/can/isotp.c
> index 54becaf6898f1..6b3d4a429042e 100644
> --- a/net/can/isotp.c
> +++ b/net/can/isotp.c
[ ... ]
> @@ -450,11 +507,15 @@ static int isotp_rcv_fc(struct isotp_sock *so, struct canfd_frame *cf, int ae)
>  		sk->sk_err = EMSGSIZE;
>  		if (!sock_flag(sk, SOCK_DEAD))
>  			sk_error_report(sk);
> +		tx_err = EMSGSIZE;
>  		fallthrough;
>  
>  	default:
>  		/* stop this tx job */
> -		so->tx.state = ISOTP_IDLE;
> +
> +		isotp_set_tx_result(so, so->tx_gen, tx_err);

[Severity: High]
This is a pre-existing issue, but does this code falsely report success
when an invalid Flow Control frame is received?

If the Flow Status is invalid (not CTS, WT, or OVFLW), it hits this
default case where tx_err is still its initial value of 0. It seems
this will store 0 (success) in tx_result and cause the sender to believe
the payload was successfully transmitted when it was actually aborted
due to a protocol violation.

> +		/* set to IDLE after publishing tx_result */
> +		smp_store_release(&so->tx.state, ISOTP_IDLE);
>  		wake_up_interruptible(&so->wait);
>  	}
>  	return 0;
[ ... ]
> @@ -1223,20 +1306,49 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
[ ... ]
>  	if (wait_tx_done) {
> -		/* wait for complete transmission of current pdu */
> -		err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
> +		/* wake up for:
> +		 * - concurrent sendmsg() claiming a new transfer
> +		 * - complete transmission of current PDU
> +		 * - shutdown state change in isotp_release()
> +		 */
> +		err = wait_event_interruptible(so->wait,
> +					       READ_ONCE(so->tx_gen) != my_gen ||
> +					       /* read pairs with the tx_result writers, SMP-safe */
> +					       smp_load_acquire(&so->tx.state) == ISOTP_IDLE ||
> +					       READ_ONCE(so->tx.state) == ISOTP_SHUTDOWN);

[Severity: High]
Can this short-circuit evaluation skip the smp_load_acquire() barrier?

If a concurrent thread has already claimed the next transfer,
READ_ONCE(so->tx_gen) != my_gen evaluates to true. The condition then
short-circuits, completely bypassing the smp_load_acquire() on so->tx.state.

Without this acquire barrier, can weakly-ordered CPUs speculatively execute
the subsequent read of tx_result inside isotp_get_tx_result() before the
read of tx_gen?

isotp_get_tx_result(struct isotp_sock *so, u32 gen) {
    u32 result = READ_ONCE(so->tx_result[gen % ISOTP_TX_RESULT_SLOTS]);
    if (isotp_get_tx_gen(result) != gen) {
        ...
        return -ECOMM;
    }
}

If so, this might read the stale result of my_gen - 4, failing the internal
generation check and causing a successful ISOTP transfer to spuriously
return -ECOMM to the user.

>  		if (err)
>  			goto err_event_drop;

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=1