Skip to content

Commit dcd5426

Browse files
edumazetdavem330
authored andcommitted
drop_monitor: fix data-race in dropmon_net_event / trace_napi_poll_hit
trace_napi_poll_hit() is reading stat->dev while another thread can write on it from dropmon_net_event() Use READ_ONCE()/WRITE_ONCE() here, RCU rules are properly enforced already, we only have to take care of load/store tearing. BUG: KCSAN: data-race in dropmon_net_event / trace_napi_poll_hit write to 0xffff88816f3ab9c0 of 8 bytes by task 20260 on cpu 1: dropmon_net_event+0xb8/0x2b0 net/core/drop_monitor.c:1579 notifier_call_chain kernel/notifier.c:84 [inline] raw_notifier_call_chain+0x53/0xb0 kernel/notifier.c:392 call_netdevice_notifiers_info net/core/dev.c:1919 [inline] call_netdevice_notifiers_extack net/core/dev.c:1931 [inline] call_netdevice_notifiers net/core/dev.c:1945 [inline] unregister_netdevice_many+0x867/0xfb0 net/core/dev.c:10415 ip_tunnel_delete_nets+0x24a/0x280 net/ipv4/ip_tunnel.c:1123 vti_exit_batch_net+0x2a/0x30 net/ipv4/ip_vti.c:515 ops_exit_list net/core/net_namespace.c:173 [inline] cleanup_net+0x4dc/0x8d0 net/core/net_namespace.c:597 process_one_work+0x3f6/0x960 kernel/workqueue.c:2307 worker_thread+0x616/0xa70 kernel/workqueue.c:2454 kthread+0x1bf/0x1e0 kernel/kthread.c:377 ret_from_fork+0x1f/0x30 read to 0xffff88816f3ab9c0 of 8 bytes by interrupt on cpu 0: trace_napi_poll_hit+0x89/0x1c0 net/core/drop_monitor.c:292 trace_napi_poll include/trace/events/napi.h:14 [inline] __napi_poll+0x36b/0x3f0 net/core/dev.c:6366 napi_poll net/core/dev.c:6432 [inline] net_rx_action+0x29e/0x650 net/core/dev.c:6519 __do_softirq+0x158/0x2de kernel/softirq.c:558 do_softirq+0xb1/0xf0 kernel/softirq.c:459 __local_bh_enable_ip+0x68/0x70 kernel/softirq.c:383 __raw_spin_unlock_bh include/linux/spinlock_api_smp.h:167 [inline] _raw_spin_unlock_bh+0x33/0x40 kernel/locking/spinlock.c:210 spin_unlock_bh include/linux/spinlock.h:394 [inline] ptr_ring_consume_bh include/linux/ptr_ring.h:367 [inline] wg_packet_decrypt_worker+0x73c/0x780 drivers/net/wireguard/receive.c:506 process_one_work+0x3f6/0x960 kernel/workqueue.c:2307 worker_thread+0x616/0xa70 kernel/workqueue.c:2454 kthread+0x1bf/0x1e0 kernel/kthread.c:377 ret_from_fork+0x1f/0x30 value changed: 0xffff88815883e000 -> 0x0000000000000000 Reported by Kernel Concurrency Sanitizer on: CPU: 0 PID: 26435 Comm: kworker/0:1 Not tainted 5.17.0-rc1-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Workqueue: wg-crypt-wg2 wg_packet_decrypt_worker Fixes: 4ea7e38 ("dropmon: add ability to detect when hardware dropsrxpackets") Signed-off-by: Eric Dumazet <[email protected]> Cc: Neil Horman <[email protected]> Reported-by: syzbot <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1de9770 commit dcd5426

File tree

1 file changed

+9
-2
lines changed

1 file changed

+9
-2
lines changed

net/core/drop_monitor.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,13 +283,17 @@ static void trace_napi_poll_hit(void *ignore, struct napi_struct *napi,
283283

284284
rcu_read_lock();
285285
list_for_each_entry_rcu(new_stat, &hw_stats_list, list) {
286+
struct net_device *dev;
287+
286288
/*
287289
* only add a note to our monitor buffer if:
288290
* 1) this is the dev we received on
289291
* 2) its after the last_rx delta
290292
* 3) our rx_dropped count has gone up
291293
*/
292-
if ((new_stat->dev == napi->dev) &&
294+
/* Paired with WRITE_ONCE() in dropmon_net_event() */
295+
dev = READ_ONCE(new_stat->dev);
296+
if ((dev == napi->dev) &&
293297
(time_after(jiffies, new_stat->last_rx + dm_hw_check_delta)) &&
294298
(napi->dev->stats.rx_dropped != new_stat->last_drop_val)) {
295299
trace_drop_common(NULL, NULL);
@@ -1576,7 +1580,10 @@ static int dropmon_net_event(struct notifier_block *ev_block,
15761580
mutex_lock(&net_dm_mutex);
15771581
list_for_each_entry_safe(new_stat, tmp, &hw_stats_list, list) {
15781582
if (new_stat->dev == dev) {
1579-
new_stat->dev = NULL;
1583+
1584+
/* Paired with READ_ONCE() in trace_napi_poll_hit() */
1585+
WRITE_ONCE(new_stat->dev, NULL);
1586+
15801587
if (trace_state == TRACE_OFF) {
15811588
list_del_rcu(&new_stat->list);
15821589
kfree_rcu(new_stat, rcu);

0 commit comments

Comments
 (0)