Re: [PATCH net 03/20] can: isotp: fix timer drain order, wakeup handling and tx_gen ordering
Oliver Hartkopp <[email protected]> Thu, 30 Jul 2026 14:28:49 +0200
| Newsgroups | org.kernel.vger.linux-can,dev.linux.lists.sashiko-reviews |
|---|---|
| Message-ID | <[email protected]> |
On 30.07.26 12:29, [email protected] wrote: > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > - [High] Silently dropped asynchronous RX socket errors in isotp_sendmsg() due to ignored return value of sock_error(sk). > -- > > --- Patch [3]: [PATCH net 03/20] can: isotp: fix timer drain order, wakeup handling and tx_gen ordering --- > commit 3e2ba28e6e9e34bb3ea9b3075735283b9c9490c0 > Author: Oliver Hartkopp <[email protected]> > can: isotp: fix timer drain order, wakeup handling and tx_gen ordering > > This commit addresses several concurrent state and timer handling issues in > the ISOTP protocol. It introduces a generation counter and packed result > array to track transfer state accurately across lock-free accesses. > > Link: https://patch.msgid.link/[email protected] > >> diff --git a/net/can/isotp.c b/net/can/isotp.c >> index 54becaf6898f1..1f11c66b343c8 100644 >> --- a/net/can/isotp.c >> +++ b/net/can/isotp.c > [ ... ] >> @@ -1223,20 +1321,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() >> + * isotp_tx_gen_done() uses common tx.state/tx_gen read sequence >> + */ >> + err = wait_event_interruptible(so->wait, >> + isotp_tx_gen_done(so, my_gen)); >> if (err) >> goto err_event_drop; >> >> - err = sock_error(sk); >> - if (err) >> - return err; >> + /* still our claim, but isotp_release() force-shut it down */ >> + if (smp_load_acquire(&so->tx.state) == ISOTP_SHUTDOWN && >> + READ_ONCE(so->tx_gen) == my_gen) { >> + err = -EADDRNOTAVAIL; >> + goto err_event_drop; >> + } >> + >> + /* own completion, or tx_gen moved on - either way this is >> + * what isotp_get_tx_result() recorded for my_gen >> + */ >> + err = isotp_get_tx_result(so, my_gen); >> + >> + /* drain to avoid stale error for a later poll()/SO_ERROR */ >> + sock_error(sk); > > [Severity: High] > Does this unconditionally clear and discard concurrent asynchronous socket > errors? > > By ignoring the return value of sock_error() here in isotp_sendmsg(), it > appears any unrelated RX errors (such as ETIMEDOUT set by > isotp_rx_timer_handler()) would be permanently lost without being reported > to the user. > > Could this cause applications to hang in recvmsg() or poll() indefinitely > because they never see the RX connection failure? > No. sk_err is a single per-socket slot shared by the RX and TX paths, so it cannot cleanly separate a TX result from a concurrent RX error. Note that a plain unreliable datagram protocol like UDP/IP gives no feedback for bad or missing received data at all - it just silently drops it. ISO-TP does a bit more and surfaces RX problems (EBADMSG/EILSEQ/ETIMEDOUT) via sk_err on a best-effort basis, which is fine: for an unreliable protocol these are ultimately caught by timeouts at a higher ISO layer anyway. What this patch fixes to 100% is the send path's POSIX contract: sendmsg() now returns the TX-specific result from tx_result[] (>0 bytes on success, <0 on a real TX error), instead of returning whatever happened to sit in sk_err - which could misreport an unrelated concurrent RX error as the TX outcome. Draining sk_err afterwards is required in CAN_ISOTP_WAIT_TX_DONE mode, since the result is delivered synchronously via the return value. So the send path is now correct and race-free; the shared-sk_err RX notification stays best-effort by design. Truly separating the two would need distinct RX/TX error channels (e.g. MSG_ERRQUEUE), which is a feature, not a fix, and out of scope here. Best regards, Oliver