Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

bonding: annotate data-races around slave->last_rx

slave->last_rx and slave->target_last_arp_rx[...] can be read and written
locklessly. Add READ_ONCE() and WRITE_ONCE() annotations.

syzbot reported:

BUG: KCSAN: data-race in bond_rcv_validate / bond_rcv_validate

write to 0xffff888149f0d428 of 8 bytes by interrupt on cpu 1:
bond_rcv_validate+0x202/0x7a0 drivers/net/bonding/bond_main.c:3335
bond_handle_frame+0xde/0x5e0 drivers/net/bonding/bond_main.c:1533
__netif_receive_skb_core+0x5b1/0x1950 net/core/dev.c:6039
__netif_receive_skb_one_core net/core/dev.c:6150 [inline]
__netif_receive_skb+0x59/0x270 net/core/dev.c:6265
netif_receive_skb_internal net/core/dev.c:6351 [inline]
netif_receive_skb+0x4b/0x2d0 net/core/dev.c:6410
...

write to 0xffff888149f0d428 of 8 bytes by interrupt on cpu 0:
bond_rcv_validate+0x202/0x7a0 drivers/net/bonding/bond_main.c:3335
bond_handle_frame+0xde/0x5e0 drivers/net/bonding/bond_main.c:1533
__netif_receive_skb_core+0x5b1/0x1950 net/core/dev.c:6039
__netif_receive_skb_one_core net/core/dev.c:6150 [inline]
__netif_receive_skb+0x59/0x270 net/core/dev.c:6265
netif_receive_skb_internal net/core/dev.c:6351 [inline]
netif_receive_skb+0x4b/0x2d0 net/core/dev.c:6410
br_netif_receive_skb net/bridge/br_input.c:30 [inline]
NF_HOOK include/linux/netfilter.h:318 [inline]
...

value changed: 0x0000000100005365 -> 0x0000000100005366

Fixes: f5b2b966f032 ("[PATCH] bonding: Validate probe replies in ARP monitor")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: syzbot <syzkaller@googlegroups.com>
Link: https://patch.msgid.link/20260122162914.2299312-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Eric Dumazet and committed by
Jakub Kicinski
f6c3665b 8016dc5e

+21 -18
+10 -8
drivers/net/bonding/bond_main.c
··· 3047 3047 __func__, &sip); 3048 3048 return; 3049 3049 } 3050 - slave->last_rx = jiffies; 3051 - slave->target_last_arp_rx[i] = jiffies; 3050 + WRITE_ONCE(slave->last_rx, jiffies); 3051 + WRITE_ONCE(slave->target_last_arp_rx[i], jiffies); 3052 3052 } 3053 3053 3054 3054 static int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, ··· 3267 3267 __func__, saddr); 3268 3268 return; 3269 3269 } 3270 - slave->last_rx = jiffies; 3271 - slave->target_last_arp_rx[i] = jiffies; 3270 + WRITE_ONCE(slave->last_rx, jiffies); 3271 + WRITE_ONCE(slave->target_last_arp_rx[i], jiffies); 3272 3272 } 3273 3273 3274 3274 static int bond_na_rcv(const struct sk_buff *skb, struct bonding *bond, ··· 3338 3338 (slave_do_arp_validate_only(bond) && is_ipv6) || 3339 3339 #endif 3340 3340 !slave_do_arp_validate_only(bond)) 3341 - slave->last_rx = jiffies; 3341 + WRITE_ONCE(slave->last_rx, jiffies); 3342 3342 return RX_HANDLER_ANOTHER; 3343 3343 } else if (is_arp) { 3344 3344 return bond_arp_rcv(skb, bond, slave); ··· 3406 3406 3407 3407 if (slave->link != BOND_LINK_UP) { 3408 3408 if (bond_time_in_interval(bond, last_tx, 1) && 3409 - bond_time_in_interval(bond, slave->last_rx, 1)) { 3409 + bond_time_in_interval(bond, READ_ONCE(slave->last_rx), 1)) { 3410 3410 3411 3411 bond_propose_link_state(slave, BOND_LINK_UP); 3412 3412 slave_state_changed = 1; ··· 3430 3430 * when the source ip is 0, so don't take the link down 3431 3431 * if we don't know our ip yet 3432 3432 */ 3433 - if (!bond_time_in_interval(bond, last_tx, bond->params.missed_max) || 3434 - !bond_time_in_interval(bond, slave->last_rx, bond->params.missed_max)) { 3433 + if (!bond_time_in_interval(bond, last_tx, 3434 + bond->params.missed_max) || 3435 + !bond_time_in_interval(bond, READ_ONCE(slave->last_rx), 3436 + bond->params.missed_max)) { 3435 3437 3436 3438 bond_propose_link_state(slave, BOND_LINK_DOWN); 3437 3439 slave_state_changed = 1;
+4 -4
drivers/net/bonding/bond_options.c
··· 1152 1152 1153 1153 if (slot >= 0 && slot < BOND_MAX_ARP_TARGETS) { 1154 1154 bond_for_each_slave(bond, slave, iter) 1155 - slave->target_last_arp_rx[slot] = last_rx; 1155 + WRITE_ONCE(slave->target_last_arp_rx[slot], last_rx); 1156 1156 targets[slot] = target; 1157 1157 } 1158 1158 } ··· 1221 1221 bond_for_each_slave(bond, slave, iter) { 1222 1222 targets_rx = slave->target_last_arp_rx; 1223 1223 for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++) 1224 - targets_rx[i] = targets_rx[i+1]; 1225 - targets_rx[i] = 0; 1224 + WRITE_ONCE(targets_rx[i], READ_ONCE(targets_rx[i+1])); 1225 + WRITE_ONCE(targets_rx[i], 0); 1226 1226 } 1227 1227 for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++) 1228 1228 targets[i] = targets[i+1]; ··· 1377 1377 1378 1378 if (slot >= 0 && slot < BOND_MAX_NS_TARGETS) { 1379 1379 bond_for_each_slave(bond, slave, iter) { 1380 - slave->target_last_arp_rx[slot] = last_rx; 1380 + WRITE_ONCE(slave->target_last_arp_rx[slot], last_rx); 1381 1381 slave_set_ns_maddr(bond, slave, target, &targets[slot]); 1382 1382 } 1383 1383 targets[slot] = *target;
+7 -6
include/net/bonding.h
··· 521 521 static inline unsigned long slave_oldest_target_arp_rx(struct bonding *bond, 522 522 struct slave *slave) 523 523 { 524 + unsigned long tmp, ret = READ_ONCE(slave->target_last_arp_rx[0]); 524 525 int i = 1; 525 - unsigned long ret = slave->target_last_arp_rx[0]; 526 526 527 - for (; (i < BOND_MAX_ARP_TARGETS) && bond->params.arp_targets[i]; i++) 528 - if (time_before(slave->target_last_arp_rx[i], ret)) 529 - ret = slave->target_last_arp_rx[i]; 530 - 527 + for (; (i < BOND_MAX_ARP_TARGETS) && bond->params.arp_targets[i]; i++) { 528 + tmp = READ_ONCE(slave->target_last_arp_rx[i]); 529 + if (time_before(tmp, ret)) 530 + ret = tmp; 531 + } 531 532 return ret; 532 533 } 533 534 ··· 538 537 if (bond->params.arp_all_targets == BOND_ARP_TARGETS_ALL) 539 538 return slave_oldest_target_arp_rx(bond, slave); 540 539 541 - return slave->last_rx; 540 + return READ_ONCE(slave->last_rx); 542 541 } 543 542 544 543 static inline void slave_update_last_tx(struct slave *slave)