Skip to content

Commit cf070fe

Browse files
hartkoppmarckleinebudde
authored andcommitted
can: isotp: serialize TX state transitions under so->rx_lock
The TX state machine (so->tx.state) is driven from three contexts: sendmsg() claiming and progressing a transfer, the RX path consuming Flow Control/echo frames, and two hrtimers timing out a stalled transfer. Mixing a lock-free cmpxchg() claim in sendmsg() with hrtimer_cancel() calls made under so->rx_lock elsewhere left windows where a frame or timer callback could act on a state that had already moved on, corrupting an unrelated transfer. so->rx_lock now covers the full lifecycle of a TX claim: sendmsg() takes it to check so->tx.state is ISOTP_IDLE, switch it to ISOTP_SENDING, bump so->tx_gen and drain the previous transfer's timers - all as one critical section. isotp_rcv_fc()/isotp_rcv_cf() already run under this lock via isotp_rcv(), and isotp_rcv_echo() now takes it itself, so none of them can ever observe a transfer mid-claim. This also means a transfer can no longer be handed to sendmsg()'s cleanup paths (signal or send error) while another thread is concurrently claiming or finishing it, so those paths can cancel timers and reset the state unconditionally. isotp_release() claims the socket the same way, so a racing sendmsg() sees a consistent ISOTP_SHUTDOWN and skips arming its timer or sending. Only the hrtimer callbacks stay outside so->rx_lock, since they run under so->rx_lock's cancellation elsewhere and taking it themselves would deadlock. so->tx_gen lets them recognize whether the transfer they timed out is still the one currently active, so they don't report an error against a transfer that has since completed or been superseded. Fixes: e057dd3 ("can: add ISO 15765-2:2016 transport protocol") Reported-by: sashiko-bot@kernel.org Closes: https://lore.kernel.org/linux-can/20260710142146.BDAE61F000E9@smtp.kernel.org/ Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Link: https://patch.msgid.link/20260712-isotp-fixes-v10-3-793a1b1ce17f@hartkopp.net Cc: stable@kernel.org Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
1 parent 20bab8b commit cf070fe

1 file changed

Lines changed: 160 additions & 42 deletions

File tree

net/can/isotp.c

Lines changed: 160 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -158,14 +158,15 @@ struct isotp_sock {
158158
canid_t rxid;
159159
ktime_t tx_gap;
160160
ktime_t lastrxcf_tstamp;
161-
struct hrtimer rxtimer, txtimer, txfrtimer;
161+
struct hrtimer rxtimer, txtimer, txfrtimer, echotimer;
162162
struct can_isotp_options opt;
163163
struct can_isotp_fc_options rxfc, txfc;
164164
struct can_isotp_ll_options ll;
165165
u32 frame_txtime;
166166
u32 force_tx_stmin;
167167
u32 force_rx_stmin;
168168
u32 cfecho; /* consecutive frame echo tag */
169+
u32 tx_gen; /* generation, bumped per new tx transfer */
169170
struct tpcon rx, tx;
170171
struct list_head notifier;
171172
wait_queue_head_t wait;
@@ -378,6 +379,15 @@ static int isotp_rcv_fc(struct isotp_sock *so, struct canfd_frame *cf, int ae)
378379

379380
hrtimer_cancel(&so->txtimer);
380381

382+
/* isotp_tx_timeout() may have given up on this job while
383+
* hrtimer_cancel() above waited for it to finish; so->rx_lock
384+
* (held by our caller isotp_rcv()) rules out a concurrent claim,
385+
* so a plain recheck is enough here.
386+
*/
387+
if (so->tx.state != ISOTP_WAIT_FC &&
388+
so->tx.state != ISOTP_WAIT_FIRST_FC)
389+
return 1;
390+
381391
if ((cf->len < ae + FC_CONTENT_SZ) ||
382392
((so->opt.flags & ISOTP_CHECK_PADDING) &&
383393
check_pad(so, cf, ae + FC_CONTENT_SZ, so->opt.rxpad_content))) {
@@ -424,7 +434,7 @@ static int isotp_rcv_fc(struct isotp_sock *so, struct canfd_frame *cf, int ae)
424434
so->tx.bs = 0;
425435
so->tx.state = ISOTP_SENDING;
426436
/* send CF frame and enable echo timeout handling */
427-
hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
437+
hrtimer_start(&so->echotimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
428438
HRTIMER_MODE_REL_SOFT);
429439
isotp_send_cframe(so);
430440
break;
@@ -577,6 +587,14 @@ static int isotp_rcv_cf(struct sock *sk, struct canfd_frame *cf, int ae,
577587

578588
hrtimer_cancel(&so->rxtimer);
579589

590+
/* isotp_rx_timer_handler() may have raced us for so->rx.state
591+
* while hrtimer_cancel() above waited for it to finish, already
592+
* reporting ETIMEDOUT and resetting the reception; don't process
593+
* this CF into a reassembly that has already been given up on.
594+
*/
595+
if (so->rx.state != ISOTP_WAIT_DATA)
596+
return 1;
597+
580598
/* CFs are never longer than the FF */
581599
if (cf->len > so->rx.ll_dl)
582600
return 1;
@@ -872,74 +890,120 @@ static void isotp_rcv_echo(struct sk_buff *skb, void *data)
872890
struct canfd_frame *cf = (struct canfd_frame *)skb->data;
873891

874892
/* only handle my own local echo CF/SF skb's (no FF!) */
875-
if (skb->sk != sk || so->cfecho != *(u32 *)cf->data)
893+
if (skb->sk != sk)
876894
return;
877895

896+
/* unlike isotp_rcv_fc()/isotp_rcv_cf(), not already under so->rx_lock
897+
* (no isotp_rcv() caller here), so take it ourselves
898+
*/
899+
spin_lock(&so->rx_lock);
900+
901+
/* so->cfecho may since belong to a new transfer; recheck under lock */
902+
if (so->cfecho != *(u32 *)cf->data)
903+
goto out_unlock;
904+
878905
/* cancel local echo timeout */
879-
hrtimer_cancel(&so->txtimer);
906+
hrtimer_cancel(&so->echotimer);
880907

881908
/* local echo skb with consecutive frame has been consumed */
882909
so->cfecho = 0;
883910

911+
/* claiming a transfer also takes so->rx_lock, so a plain recheck
912+
* is enough: so->tx.state can't have flipped to ISOTP_SENDING for
913+
* a new claim while we're still in here
914+
*/
915+
if (so->tx.state != ISOTP_SENDING)
916+
goto out_unlock;
917+
884918
if (so->tx.idx >= so->tx.len) {
885919
/* we are done */
886920
so->tx.state = ISOTP_IDLE;
887921
wake_up_interruptible(&so->wait);
888-
return;
922+
goto out_unlock;
889923
}
890924

891925
if (so->txfc.bs && so->tx.bs >= so->txfc.bs) {
892926
/* stop and wait for FC with timeout */
893927
so->tx.state = ISOTP_WAIT_FC;
894928
hrtimer_start(&so->txtimer, ktime_set(ISOTP_FC_TIMEOUT, 0),
895929
HRTIMER_MODE_REL_SOFT);
896-
return;
930+
goto out_unlock;
897931
}
898932

899933
/* no gap between data frames needed => use burst mode */
900934
if (!so->tx_gap) {
901935
/* enable echo timeout handling */
902-
hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
936+
hrtimer_start(&so->echotimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
903937
HRTIMER_MODE_REL_SOFT);
904938
isotp_send_cframe(so);
905-
return;
939+
goto out_unlock;
906940
}
907941

908942
/* start timer to send next consecutive frame with correct delay */
909943
hrtimer_start(&so->txfrtimer, so->tx_gap, HRTIMER_MODE_REL_SOFT);
944+
945+
out_unlock:
946+
spin_unlock(&so->rx_lock);
910947
}
911948

912-
static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
949+
/* shared by so->txtimer's and so->echotimer's callbacks. Both timers get
950+
* cancelled under so->rx_lock elsewhere, so this must stay lock-free to
951+
* avoid deadlocking with that; uses so->tx_gen instead to avoid tainting
952+
* a new transfer with an error from the one that just timed out.
953+
*/
954+
static enum hrtimer_restart isotp_tx_timeout(struct isotp_sock *so)
913955
{
914-
struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
915-
txtimer);
916956
struct sock *sk = &so->sk;
957+
u32 gen = READ_ONCE(so->tx_gen);
958+
u32 old_state = READ_ONCE(so->tx.state);
917959

918960
/* don't handle timeouts in IDLE or SHUTDOWN state */
919-
if (so->tx.state == ISOTP_IDLE || so->tx.state == ISOTP_SHUTDOWN)
961+
if (old_state == ISOTP_IDLE || old_state == ISOTP_SHUTDOWN)
962+
return HRTIMER_NORESTART;
963+
964+
/* only claim the timeout if the state is still unchanged */
965+
if (cmpxchg(&so->tx.state, old_state, ISOTP_IDLE) != old_state)
920966
return HRTIMER_NORESTART;
921967

922968
/* we did not get any flow control or echo frame in time */
923969

924-
/* report 'communication error on send' */
925-
sk->sk_err = ECOMM;
926-
if (!sock_flag(sk, SOCK_DEAD))
927-
sk_error_report(sk);
970+
if (READ_ONCE(so->tx_gen) == gen) {
971+
/* report 'communication error on send' */
972+
sk->sk_err = ECOMM;
973+
if (!sock_flag(sk, SOCK_DEAD))
974+
sk_error_report(sk);
975+
}
928976

929-
/* reset tx state */
930-
so->tx.state = ISOTP_IDLE;
931977
wake_up_interruptible(&so->wait);
932978

933979
return HRTIMER_NORESTART;
934980
}
935981

982+
/* so->txtimer: fires when a Flow Control frame does not arrive in time */
983+
static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
984+
{
985+
struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
986+
txtimer);
987+
988+
return isotp_tx_timeout(so);
989+
}
990+
991+
/* so->echotimer: fires when a sent CF/SF's local echo does not arrive */
992+
static enum hrtimer_restart isotp_echo_timer_handler(struct hrtimer *hrtimer)
993+
{
994+
struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
995+
echotimer);
996+
997+
return isotp_tx_timeout(so);
998+
}
999+
9361000
static enum hrtimer_restart isotp_txfr_timer_handler(struct hrtimer *hrtimer)
9371001
{
9381002
struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
9391003
txfrtimer);
9401004

9411005
/* start echo timeout handling and cover below protocol error */
942-
hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
1006+
hrtimer_start(&so->echotimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
9431007
HRTIMER_MODE_REL_SOFT);
9441008

9451009
/* cfecho should be consumed by isotp_rcv_echo() here */
@@ -960,13 +1024,24 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
9601024
int ae = (so->opt.flags & CAN_ISOTP_EXTEND_ADDR) ? 1 : 0;
9611025
int wait_tx_done = (so->opt.flags & CAN_ISOTP_WAIT_TX_DONE) ? 1 : 0;
9621026
s64 hrtimer_sec = ISOTP_ECHO_TIMEOUT;
1027+
struct hrtimer *tx_hrt = &so->echotimer;
1028+
u32 new_state = ISOTP_SENDING;
9631029
int off;
9641030
int err;
9651031

9661032
if (!so->bound || so->tx.state == ISOTP_SHUTDOWN)
9671033
return -EADDRNOTAVAIL;
9681034

969-
while (cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SENDING) != ISOTP_IDLE) {
1035+
/* claim the socket under so->rx_lock: this serializes the claim
1036+
* with the RX path and with sendmsg()'s own error paths below, so
1037+
* none of them can ever see a transfer mid-claim
1038+
*/
1039+
for (;;) {
1040+
spin_lock_bh(&so->rx_lock);
1041+
if (READ_ONCE(so->tx.state) == ISOTP_IDLE)
1042+
break;
1043+
spin_unlock_bh(&so->rx_lock);
1044+
9701045
/* we do not support multiple buffers - for now */
9711046
if (msg->msg_flags & MSG_DONTWAIT)
9721047
return -EAGAIN;
@@ -975,11 +1050,23 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
9751050
return -EADDRNOTAVAIL;
9761051

9771052
/* wait for complete transmission of current pdu */
978-
err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
1053+
err = wait_event_interruptible(so->wait,
1054+
so->tx.state == ISOTP_IDLE);
9791055
if (err)
980-
goto err_event_drop;
1056+
return err;
9811057
}
9821058

1059+
/* new transfer: bump so->tx_gen and drain the old one's timers,
1060+
* still under the so->rx_lock we just claimed the socket with
1061+
*/
1062+
WRITE_ONCE(so->tx.state, ISOTP_SENDING);
1063+
WRITE_ONCE(so->tx_gen, READ_ONCE(so->tx_gen) + 1);
1064+
hrtimer_cancel(&so->txtimer);
1065+
hrtimer_cancel(&so->echotimer);
1066+
hrtimer_cancel(&so->txfrtimer);
1067+
so->cfecho = 0;
1068+
spin_unlock_bh(&so->rx_lock);
1069+
9831070
/* so->bound is only checked once above - a wakeup may have
9841071
* unbound/rebound the socket meanwhile, so re-validate it
9851072
*/
@@ -1096,18 +1183,33 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
10961183
so->cfecho = *(u32 *)cf->data;
10971184
} else {
10981185
/* standard flow control check */
1099-
so->tx.state = ISOTP_WAIT_FIRST_FC;
1186+
new_state = ISOTP_WAIT_FIRST_FC;
11001187

11011188
/* start timeout for FC */
11021189
hrtimer_sec = ISOTP_FC_TIMEOUT;
1190+
tx_hrt = &so->txtimer;
11031191

11041192
/* no CF echo tag for isotp_rcv_echo() (FF-mode) */
11051193
so->cfecho = 0;
11061194
}
11071195
}
11081196

1109-
hrtimer_start(&so->txtimer, ktime_set(hrtimer_sec, 0),
1197+
spin_lock_bh(&so->rx_lock);
1198+
if (so->tx.state == ISOTP_SHUTDOWN) {
1199+
/* isotp_release() has since taken over and already drained
1200+
* our timers - don't send into a socket that's going away
1201+
*/
1202+
spin_unlock_bh(&so->rx_lock);
1203+
kfree_skb(skb);
1204+
dev_put(dev);
1205+
wake_up_interruptible(&so->wait);
1206+
return -EADDRNOTAVAIL;
1207+
}
1208+
/* WAIT_FIRST_FC for standard FF, else stays ISOTP_SENDING */
1209+
so->tx.state = new_state;
1210+
hrtimer_start(tx_hrt, ktime_set(hrtimer_sec, 0),
11101211
HRTIMER_MODE_REL_SOFT);
1212+
spin_unlock_bh(&so->rx_lock);
11111213

11121214
/* send the first or only CAN frame */
11131215
cf->flags = so->ll.tx_flags;
@@ -1120,13 +1222,10 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
11201222
pr_notice_once("can-isotp: %s: can_send_ret %pe\n",
11211223
__func__, ERR_PTR(err));
11221224

1225+
spin_lock_bh(&so->rx_lock);
11231226
/* no transmission -> no timeout monitoring */
1124-
hrtimer_cancel(&so->txtimer);
1125-
1126-
/* reset consecutive frame echo tag */
1127-
so->cfecho = 0;
1128-
1129-
goto err_out_drop;
1227+
hrtimer_cancel(tx_hrt);
1228+
goto err_out_drop_locked;
11301229
}
11311230

11321231
if (wait_tx_done) {
@@ -1142,14 +1241,21 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
11421241

11431242
return size;
11441243

1244+
err_out_drop:
1245+
/* claimed but nothing sent yet - no timer to cancel */
1246+
spin_lock_bh(&so->rx_lock);
1247+
goto err_out_drop_locked;
11451248
err_event_drop:
1146-
/* got signal: force tx state machine to be idle */
1147-
so->tx.state = ISOTP_IDLE;
1249+
/* interrupted waiting on our own transfer - drain its timers */
1250+
spin_lock_bh(&so->rx_lock);
11481251
hrtimer_cancel(&so->txfrtimer);
11491252
hrtimer_cancel(&so->txtimer);
1150-
err_out_drop:
1151-
/* drop this PDU and unlock a potential wait queue */
1253+
hrtimer_cancel(&so->echotimer);
1254+
err_out_drop_locked:
1255+
/* release the claim; so->rx_lock still held from above */
1256+
so->cfecho = 0;
11521257
so->tx.state = ISOTP_IDLE;
1258+
spin_unlock_bh(&so->rx_lock);
11531259
wake_up_interruptible(&so->wait);
11541260

11551261
return err;
@@ -1211,13 +1317,20 @@ static int isotp_release(struct socket *sock)
12111317
so = isotp_sk(sk);
12121318
net = sock_net(sk);
12131319

1214-
/* wait for complete transmission of current pdu */
1215-
while (wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE) == 0 &&
1216-
cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SHUTDOWN) != ISOTP_IDLE)
1320+
/* best-effort: wait for a running pdu to finish, but don't block on
1321+
* it forever - give up after the first signal
1322+
*/
1323+
while (so->tx.state != ISOTP_IDLE &&
1324+
wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE) == 0)
12171325
;
12181326

1219-
/* force state machines to be idle also when a signal occurred */
1327+
/* claim the socket under so->rx_lock like sendmsg() does, so its
1328+
* claim can't race the forced ISOTP_SHUTDOWN below; force it
1329+
* unconditionally, even when a signal cut the wait above short
1330+
*/
1331+
spin_lock_bh(&so->rx_lock);
12201332
so->tx.state = ISOTP_SHUTDOWN;
1333+
spin_unlock_bh(&so->rx_lock);
12211334
so->rx.state = ISOTP_IDLE;
12221335

12231336
spin_lock(&isotp_notifier_lock);
@@ -1263,6 +1376,7 @@ static int isotp_release(struct socket *sock)
12631376

12641377
hrtimer_cancel(&so->txfrtimer);
12651378
hrtimer_cancel(&so->txtimer);
1379+
hrtimer_cancel(&so->echotimer);
12661380
hrtimer_cancel(&so->rxtimer);
12671381

12681382
sock_orphan(sk);
@@ -1702,10 +1816,14 @@ static int isotp_init(struct sock *sk)
17021816
so->rx.buflen = ARRAY_SIZE(so->rx.sbuf);
17031817
so->tx.buflen = ARRAY_SIZE(so->tx.sbuf);
17041818

1705-
hrtimer_setup(&so->rxtimer, isotp_rx_timer_handler, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
1706-
hrtimer_setup(&so->txtimer, isotp_tx_timer_handler, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
1707-
hrtimer_setup(&so->txfrtimer, isotp_txfr_timer_handler, CLOCK_MONOTONIC,
1708-
HRTIMER_MODE_REL_SOFT);
1819+
hrtimer_setup(&so->rxtimer, isotp_rx_timer_handler,
1820+
CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
1821+
hrtimer_setup(&so->txtimer, isotp_tx_timer_handler,
1822+
CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
1823+
hrtimer_setup(&so->echotimer, isotp_echo_timer_handler,
1824+
CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
1825+
hrtimer_setup(&so->txfrtimer, isotp_txfr_timer_handler,
1826+
CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
17091827

17101828
init_waitqueue_head(&so->wait);
17111829
spin_lock_init(&so->rx_lock);

0 commit comments

Comments
 (0)