In the Linux kernel, the following vulnerability has been resolved:
net: watchdog: fix refcount tracking races
Blamed commit converted the untracked devhold()/devput() calls in the watchdog code to use the tracked devholdtrack()/devputtrack() (which were later renamed/interfaced to netdevhold() and netdevput()).
By introducing dev->watchdogdevtracker to store the reference tracking information without adding synchronization between netdevwatchdogup() and dev_watchdog(), it enabled the race condition where this pointer could be overwritten or freed concurrently, leading to the list corruption crash syzbot reported:
listdel corruption, ffff888114a18c00->next is NULL kernel BUG at lib/listdebug.c:52 ! Oops: invalid opcode: 0000 [#1] SMP KASAN PTI CPU: 1 UID: 0 PID: 91 Comm: kworker/u8:5 Not tainted syzkaller #0 PREEMPT(lazy) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/09/2026 Workqueue: eventsunbound linkwatchevent RIP: 0010:__listdelentryvalidorreport.cold+0x22/0x2a lib/listdebug.c:52 Call Trace: <TASK> __listdelentry_valid include/linux/list.h:132 [inline] __listdelentry include/linux/list.h:246 [inline] listmovetail include/linux/list.h:341 [inline] reftrackerfree+0x1a7/0x6c0 lib/reftracker.c:329 netdevtrackerfree include/linux/netdevice.h:4491 [inline] netdevput include/linux/netdevice.h:4508 [inline] netdevput include/linux/netdevice.h:4504 [inline] netdevwatchdogdown net/sched/schgeneric.c:600 [inline] devdeactivatemany+0x28c/0xfe0 net/sched/schgeneric.c:1363 devdeactivate+0x109/0x1d0 net/sched/schgeneric.c:1397 linkwatchdodev net/core/linkwatch.c:184 [inline] linkwatchdodev+0xd3/0x120 net/core/link_watch.c:166 __linkwatchrunqueue+0x3a5/0x810 net/core/linkwatch.c:240 linkwatchevent+0x8f/0xc0 net/core/linkwatch.c:314 processonework+0xa0e/0x1980 kernel/workqueue.c:3314 processscheduledworks kernel/workqueue.c:3397 [inline] workerthread+0x5ef/0xe50 kernel/workqueue.c:3478 kthread+0x370/0x450 kernel/kthread.c:436 retfromfork+0x69a/0xc80 arch/x86/kernel/process.c:158 retfromforkasm+0x1a/0x30 arch/x86/entry/entry64.S:245
This patch has three coordinated parts:
1) Add dev->watchdoglock and dev->watchdogref_held to serialize watchdog operations.
2) Remove netdevwatchdogup() call from netifcarrieron(): This ensures netdevwatchdogup() is only called from process/BH context (via linkwatch workqueue devactivate()), allowing us to use spinlock_bh() for synchronization.
3) Synchronize watchdog up and watchdog timer: Protect netdevwatchdogup() with txgloballock and watchdoglock. Only allocate a new tracker in netdevwatchdogup() if one is not already present. In devwatchdog(), ensure we don't release the tracker if the timer was rescheduled either by devwatchdog() itself or concurrently by netdevwatchdog_up().