Skip to content

Commit 749179c

Browse files
hartkoppmarckleinebudde
authored andcommitted
can: bcm: add locking when updating filter and timer values
KCSAN detected a simultaneous access to timer values that can be overwritten in bcm_rx_setup() when updating timer and filter content while bcm_rx_handler(), bcm_rx_timeout_handler() or bcm_rx_thr_handler() run concurrently on incoming CAN traffic. Protect the timer (ival1/ival2/kt_ival1/kt_ival2/kt_lastmsg) and filter (nframes/flags/frames/last_frames) updates in bcm_rx_setup() with a new per-op bcm_rx_update_lock, taken with the matching scope in the RX handlers. memcpy_from_msg() is staged into a temporary buffer before the lock is taken, since it can sleep and must not run under a spinlock. hrtimer_cancel() is always called without bcm_rx_update_lock held, since bcm_rx_timeout_handler()/bcm_rx_thr_handler() take the same lock and a running callback would otherwise deadlock against the canceller. Also close a related race: bcm_rx_setup() cleared the RTR flag in the stored reply frame's can_id as a separate, unprotected step after the frame content was already installed, so a concurrent bcm_rx_handler() could transmit a stale reply with CAN_RTR_FLAG still set. Fold that normalization into the initial frame preparation instead (on the staged buffer for updates, directly on op->frames pre-registration for new ops), so the installed frame is always atomically self-consistent. bcm_rx_handler()'s RX_RTR_FRAME check now takes a lock-protected snapshot of op->flags before deciding whether to call bcm_can_tx(), but does not hold the lock across that call. Also take a lock-protected snapshot of the currframe in bcm_can_tx() to avoid partly overwrites by content updates in bcm_tx_setup(). Finally check if a TX_RESET_MULTI_IDX/SETTIMER might have reset op->currframe between the two locked sections in bcm_can_tx(). Omit calling hrtimer_forward() with zero interval in bcm_rx_thr_handler(). kt_ival2 may have been concurrently cleared by bcm_rx_setup() before it cancels this timer, so check kt_ival2 inside the bcm_rx_update_lock. Fixes: c2aba69 ("can: bcm: add locking for bcm_op runtime updates") Reported-by: syzbot+75e5e4ae00c3b4bb544e@syzkaller.appspotmail.com Closes: https://lore.kernel.org/linux-can/6975d5cf.a00a0220.33ccc7.0022.GAE@google.com/ Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Link: https://patch.msgid.link/20260714-bcm_fixes-v15-3-562f7e3e42da@hartkopp.net Cc: stable@kernel.org Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
1 parent d9b091d commit 749179c

1 file changed

Lines changed: 133 additions & 43 deletions

File tree

net/can/bcm.c

Lines changed: 133 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ struct bcm_op {
129129
struct sock *sk;
130130
struct net_device *rx_reg_dev;
131131
spinlock_t bcm_tx_lock; /* protect currframe/count in runtime updates */
132+
spinlock_t bcm_rx_update_lock; /* protect filter/timer data updates */
132133
};
133134

134135
struct bcm_sock {
@@ -293,22 +294,28 @@ static int bcm_proc_show(struct seq_file *m, void *v)
293294
* bcm_can_tx - send the (next) CAN frame to the appropriate CAN interface
294295
* of the given bcm tx op
295296
*/
296-
static void bcm_can_tx(struct bcm_op *op)
297+
static void bcm_can_tx(struct bcm_op *op, struct canfd_frame *cf)
297298
{
298299
struct sk_buff *skb;
299300
struct can_skb_ext *csx;
300301
struct net_device *dev;
301-
struct canfd_frame *cf;
302+
struct canfd_frame cframe;
303+
bool cyclic = !cf;
304+
unsigned int idx = 0;
302305
int err;
303306

304307
/* no target device? => exit */
305308
if (!op->ifindex)
306309
return;
307310

308-
/* read currframe under lock protection */
309-
spin_lock_bh(&op->bcm_tx_lock);
310-
cf = op->frames + op->cfsiz * op->currframe;
311-
spin_unlock_bh(&op->bcm_tx_lock);
311+
if (cyclic) {
312+
/* read currframe under lock protection */
313+
spin_lock_bh(&op->bcm_tx_lock);
314+
idx = op->currframe;
315+
memcpy(&cframe, op->frames + op->cfsiz * idx, op->cfsiz);
316+
cf = &cframe;
317+
spin_unlock_bh(&op->bcm_tx_lock);
318+
}
312319

313320
dev = dev_get_by_index(sock_net(op->sk), op->ifindex);
314321
if (!dev) {
@@ -341,14 +348,20 @@ static void bcm_can_tx(struct bcm_op *op)
341348
if (!err)
342349
op->frames_abs++;
343350

344-
op->currframe++;
351+
/* only advance the cyclic sequence if nothing reset currframe while
352+
* we were sending - a concurrent TX_RESET_MULTI_IDX means this
353+
* frame's bookkeeping belongs to a sequence that no longer exists
354+
*/
355+
if (!cyclic || op->currframe == idx) {
356+
op->currframe++;
345357

346-
/* reached last frame? */
347-
if (op->currframe >= op->nframes)
348-
op->currframe = 0;
358+
/* reached last frame? */
359+
if (op->currframe >= op->nframes)
360+
op->currframe = 0;
349361

350-
if (op->count > 0)
351-
op->count--;
362+
if (op->count > 0)
363+
op->count--;
364+
}
352365

353366
spin_unlock_bh(&op->bcm_tx_lock);
354367
out:
@@ -461,7 +474,7 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
461474
struct bcm_msg_head msg_head;
462475

463476
if (op->kt_ival1 && (op->count > 0)) {
464-
bcm_can_tx(op);
477+
bcm_can_tx(op, NULL);
465478
if (!op->count && (op->flags & TX_COUNTEVT)) {
466479

467480
/* create notification to user */
@@ -478,7 +491,7 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
478491
}
479492

480493
} else if (op->kt_ival2) {
481-
bcm_can_tx(op);
494+
bcm_can_tx(op, NULL);
482495
}
483496

484497
return bcm_tx_set_expiry(op, &op->timer) ?
@@ -622,6 +635,8 @@ static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
622635
struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
623636
struct bcm_msg_head msg_head;
624637

638+
spin_lock_bh(&op->bcm_rx_update_lock);
639+
625640
/* if user wants to be informed, when cyclic CAN-Messages come back */
626641
if ((op->flags & RX_ANNOUNCE_RESUME) && op->last_frames) {
627642
/* clear received CAN frames to indicate 'nothing received' */
@@ -638,6 +653,8 @@ static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
638653
msg_head.can_id = op->can_id;
639654
msg_head.nframes = 0;
640655

656+
spin_unlock_bh(&op->bcm_rx_update_lock);
657+
641658
bcm_send_to_user(op, &msg_head, NULL, 0);
642659

643660
return HRTIMER_NORESTART;
@@ -686,15 +703,26 @@ static int bcm_rx_thr_flush(struct bcm_op *op)
686703
static enum hrtimer_restart bcm_rx_thr_handler(struct hrtimer *hrtimer)
687704
{
688705
struct bcm_op *op = container_of(hrtimer, struct bcm_op, thrtimer);
706+
enum hrtimer_restart ret;
689707

690-
if (bcm_rx_thr_flush(op)) {
708+
spin_lock_bh(&op->bcm_rx_update_lock);
709+
710+
/* kt_ival2 may have been concurrently cleared by bcm_rx_setup()
711+
* before it cancels this timer - never forward with a zero
712+
* interval in that case.
713+
*/
714+
if (bcm_rx_thr_flush(op) && op->kt_ival2) {
691715
hrtimer_forward_now(hrtimer, op->kt_ival2);
692-
return HRTIMER_RESTART;
716+
ret = HRTIMER_RESTART;
693717
} else {
694718
/* rearm throttle handling */
695719
op->kt_lastmsg = 0;
696-
return HRTIMER_NORESTART;
720+
ret = HRTIMER_NORESTART;
697721
}
722+
723+
spin_unlock_bh(&op->bcm_rx_update_lock);
724+
725+
return ret;
698726
}
699727

700728
/*
@@ -704,8 +732,10 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data)
704732
{
705733
struct bcm_op *op = (struct bcm_op *)data;
706734
const struct canfd_frame *rxframe = (struct canfd_frame *)skb->data;
735+
struct canfd_frame rtrframe;
707736
unsigned int i;
708737
unsigned char traffic_flags;
738+
bool rtr_frame;
709739

710740
if (op->can_id != rxframe->can_id)
711741
return;
@@ -729,9 +759,18 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data)
729759
/* update statistics */
730760
op->frames_abs++;
731761

732-
if (op->flags & RX_RTR_FRAME) {
762+
/* snapshot the flag under lock: op->flags/op->frames may be updated
763+
* concurrently by bcm_rx_setup().
764+
*/
765+
spin_lock_bh(&op->bcm_rx_update_lock);
766+
rtr_frame = op->flags & RX_RTR_FRAME;
767+
if (rtr_frame)
768+
memcpy(&rtrframe, op->frames, op->cfsiz);
769+
spin_unlock_bh(&op->bcm_rx_update_lock);
770+
771+
if (rtr_frame) {
733772
/* send reply for RTR-request (placed in op->frames[0]) */
734-
bcm_can_tx(op);
773+
bcm_can_tx(op, &rtrframe);
735774
return;
736775
}
737776

@@ -743,6 +782,8 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data)
743782
traffic_flags |= RX_OWN;
744783
}
745784

785+
spin_lock_bh(&op->bcm_rx_update_lock);
786+
746787
if (op->flags & RX_FILTER_ID) {
747788
/* the easiest case */
748789
bcm_rx_update_and_send(op, op->last_frames, rxframe,
@@ -778,6 +819,8 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data)
778819

779820
rx_starttimer:
780821
bcm_rx_starttimer(op);
822+
823+
spin_unlock_bh(&op->bcm_rx_update_lock);
781824
}
782825

783826
/*
@@ -1116,7 +1159,7 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
11161159
}
11171160

11181161
if (op->flags & TX_ANNOUNCE)
1119-
bcm_can_tx(op);
1162+
bcm_can_tx(op, NULL);
11201163

11211164
if (op->flags & STARTTIMER)
11221165
bcm_tx_start_timer(op);
@@ -1130,6 +1173,24 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
11301173
return err;
11311174
}
11321175

1176+
static void bcm_rx_setup_rtr_check(struct bcm_msg_head *msg_head,
1177+
struct bcm_op *op, void *new_frames)
1178+
{
1179+
/* funny feature in RX(!)_SETUP only for RTR-mode:
1180+
* copy can_id into frame BUT without RTR-flag to
1181+
* prevent a full-load-loopback-test ... ;-]
1182+
* normalize this on the staged buffer, before it is
1183+
* ever installed into op->frames.
1184+
*/
1185+
if (msg_head->flags & RX_RTR_FRAME) {
1186+
struct canfd_frame *frame0 = new_frames;
1187+
1188+
if ((msg_head->flags & TX_CP_CAN_ID) ||
1189+
frame0->can_id == op->can_id)
1190+
frame0->can_id = op->can_id & ~CAN_RTR_FLAG;
1191+
}
1192+
}
1193+
11331194
/*
11341195
* bcm_rx_setup - create or update a bcm rx op (for bcm_sendmsg)
11351196
*/
@@ -1164,6 +1225,8 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
11641225
/* check the given can_id */
11651226
op = bcm_find_op(&bo->rx_ops, msg_head, ifindex);
11661227
if (op) {
1228+
void *new_frames = NULL;
1229+
11671230
/* update existing BCM operation */
11681231

11691232
/*
@@ -1175,19 +1238,48 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
11751238
return -E2BIG;
11761239

11771240
if (msg_head->nframes) {
1178-
/* update CAN frames content */
1179-
err = memcpy_from_msg(op->frames, msg,
1241+
/* get new CAN frames content before locking */
1242+
new_frames = kmalloc(msg_head->nframes * op->cfsiz,
1243+
GFP_KERNEL);
1244+
if (!new_frames)
1245+
return -ENOMEM;
1246+
1247+
err = memcpy_from_msg(new_frames, msg,
11801248
msg_head->nframes * op->cfsiz);
1181-
if (err < 0)
1249+
if (err < 0) {
1250+
kfree(new_frames);
11821251
return err;
1252+
}
11831253

1184-
/* clear last_frames to indicate 'nothing received' */
1185-
memset(op->last_frames, 0, msg_head->nframes * op->cfsiz);
1254+
bcm_rx_setup_rtr_check(msg_head, op, new_frames);
11861255
}
11871256

1257+
spin_lock_bh(&op->bcm_rx_update_lock);
11881258
op->nframes = msg_head->nframes;
11891259
op->flags = msg_head->flags;
11901260

1261+
if (msg_head->nframes) {
1262+
/* update CAN frames content */
1263+
memcpy(op->frames, new_frames,
1264+
msg_head->nframes * op->cfsiz);
1265+
1266+
/* clear last_frames to indicate 'nothing received' */
1267+
memset(op->last_frames, 0,
1268+
msg_head->nframes * op->cfsiz);
1269+
}
1270+
1271+
if (msg_head->flags & SETTIMER) {
1272+
op->ival1 = msg_head->ival1;
1273+
op->ival2 = msg_head->ival2;
1274+
op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1);
1275+
op->kt_ival2 = bcm_timeval_to_ktime(msg_head->ival2);
1276+
op->kt_lastmsg = 0;
1277+
}
1278+
spin_unlock_bh(&op->bcm_rx_update_lock);
1279+
1280+
/* free temporary frames / kfree(NULL) is safe */
1281+
kfree(new_frames);
1282+
11911283
/* Only an update -> do not call can_rx_register() */
11921284
do_rx_register = 0;
11931285

@@ -1198,6 +1290,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
11981290
return -ENOMEM;
11991291

12001292
spin_lock_init(&op->bcm_tx_lock);
1293+
spin_lock_init(&op->bcm_rx_update_lock);
12011294
op->can_id = msg_head->can_id;
12021295
op->nframes = msg_head->nframes;
12031296
op->cfsiz = CFSIZ(msg_head->flags);
@@ -1239,6 +1332,8 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
12391332
kfree(op);
12401333
return err;
12411334
}
1335+
1336+
bcm_rx_setup_rtr_check(msg_head, op, op->frames);
12421337
}
12431338

12441339
/* bcm_can_tx / bcm_tx_timeout_handler needs this */
@@ -1266,29 +1361,22 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
12661361
/* check flags */
12671362

12681363
if (op->flags & RX_RTR_FRAME) {
1269-
struct canfd_frame *frame0 = op->frames;
1270-
12711364
/* no timers in RTR-mode */
12721365
hrtimer_cancel(&op->thrtimer);
12731366
hrtimer_cancel(&op->timer);
1274-
1275-
/*
1276-
* funny feature in RX(!)_SETUP only for RTR-mode:
1277-
* copy can_id into frame BUT without RTR-flag to
1278-
* prevent a full-load-loopback-test ... ;-]
1279-
*/
1280-
if ((op->flags & TX_CP_CAN_ID) ||
1281-
(frame0->can_id == op->can_id))
1282-
frame0->can_id = op->can_id & ~CAN_RTR_FLAG;
1283-
12841367
} else {
12851368
if (op->flags & SETTIMER) {
12861369

1287-
/* set timer value */
1288-
op->ival1 = msg_head->ival1;
1289-
op->ival2 = msg_head->ival2;
1290-
op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1);
1291-
op->kt_ival2 = bcm_timeval_to_ktime(msg_head->ival2);
1370+
/* set timers (locked) for newly created op */
1371+
if (do_rx_register) {
1372+
spin_lock_bh(&op->bcm_rx_update_lock);
1373+
op->ival1 = msg_head->ival1;
1374+
op->ival2 = msg_head->ival2;
1375+
op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1);
1376+
op->kt_ival2 = bcm_timeval_to_ktime(msg_head->ival2);
1377+
op->kt_lastmsg = 0;
1378+
spin_unlock_bh(&op->bcm_rx_update_lock);
1379+
}
12921380

12931381
/* disable an active timer due to zero value? */
12941382
if (!op->kt_ival1)
@@ -1298,9 +1386,11 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
12981386
* In any case cancel the throttle timer, flush
12991387
* potentially blocked msgs and reset throttle handling
13001388
*/
1301-
op->kt_lastmsg = 0;
13021389
hrtimer_cancel(&op->thrtimer);
1390+
1391+
spin_lock_bh(&op->bcm_rx_update_lock);
13031392
bcm_rx_thr_flush(op);
1393+
spin_unlock_bh(&op->bcm_rx_update_lock);
13041394
}
13051395

13061396
if ((op->flags & STARTTIMER) && op->kt_ival1)

0 commit comments

Comments
 (0)