[PATCH RFC] net/sched: fix watchdog timer teardown race

0 views
Skip to first unread message

syzbot

unread,
May 13, 2026, 5:16:11 PM (2 days ago) May 13
to syzkaller-upst...@googlegroups.com, syz...@lists.linux.dev
A race condition exists between network device unregistration and
concurrent link state change events (e.g., usbnet_deferred_kevent).
During device unregistration, __dev_close_many() clears
__LINK_STATE_START and calls netdev_watchdog_down() to delete the
watchdog timer. However, a concurrent link state change can call
netif_carrier_on(), which checks netif_running(dev). If this check
happens before __LINK_STATE_START is cleared, it proceeds to call
netdev_watchdog_up(). If netdev_watchdog_up() is delayed and executes
after netdev_watchdog_down() has deleted the timer, it will re-arm the
timer. This leaves the timer armed during the final teardown phase,
eventually triggering the WARN_ON(timer_pending(&dev->watchdog_timer))
in dev_shutdown().

Attempting to fix this by adding a lock-free double-check in
netdev_watchdog_up() introduces a subtle refcount underflow bug.
Instead, the most robust approach is to ensure the timer is completely
dead during the final teardown phase. Since dev_shutdown() is called
from process context under the rtnl_lock(), it is safe to sleep and
block. We can use timer_delete_sync() in dev_shutdown() to deactivate
the timer and wait for any concurrently running callbacks to finish. If
the timer was left armed, timer_delete_sync() returns 1, allowing us to
safely call netdev_put() to balance the refcount. This guarantees that
the timer is definitively dead before the WARN_ON check.

Fixes: d7811e623dd4be3e3bdba2d6330f7f15541ee45f ("[NET]: Drop tx lock in dev_watchdog_up")
Assisted-by: Gemini:gemini-3.1-pro-preview Gemini:gemini-3-flash-preview
Reported-by: syzbot+c9ecf6...@syzkaller.appspotmail.com
Link: https://syzkaller.appspot.com/bug?extid=c9ecf60a8adb7629821e
Link: https://syzkaller.appspot.com/ai_job?id=2f0da36f-92ca-4f82-a3f9-92648d57a2ae
To: <da...@davemloft.net>
To: <edum...@google.com>
To: <j...@mojatatu.com>
To: <ji...@resnulli.us>
To: <ku...@kernel.org>
To: <net...@vger.kernel.org>
To: <pab...@redhat.com>
Cc: <ho...@kernel.org>
Cc: <linux-...@vger.kernel.org>

---
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index a93321db8..e4e72077b 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -1493,6 +1493,8 @@ void dev_shutdown(struct net_device *dev)
qdisc_put(rtnl_dereference(dev->qdisc));
rcu_assign_pointer(dev->qdisc, &noop_qdisc);

+ if (timer_delete_sync(&dev->watchdog_timer))
+ netdev_put(dev, &dev->watchdog_dev_tracker);
WARN_ON(timer_pending(&dev->watchdog_timer));
}



base-commit: 5d6919055dec134de3c40167a490f33c74c12581
--
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to send it to the mailing list.
Reply with '#syz reject' to reject it.

See for more information.
Reply all
Reply to author
Forward
0 new messages