CVE-2026-74264: net: watchdog: fix refcount tracking races
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 devwatchdog(), 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> listdelentryvalid 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/linkwatch.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->watchdogrefheld 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 spinlockbh() 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 netdevwatchdogup().
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Configuration
Remove the netdev_watchdog_up() call from netif_carrier_on() (as described: “Remove netdev_watchdog_up() call from netif_carrier_on()”).
Linux kernel netdev watchdog / net/core netdev_watchdog_up() call sites (remove from netif_carrier_on) = remove - Configuration
Add dev->watchdog_lock and dev->watchdog_ref_held to serialize watchdog operations (as described: “Add dev->watchdog_lock and dev->watchdog_ref_held to serialize watchdog operations.”).
Linux kernel netdev watchdog / reference tracking dev->watchdog_lock / dev->watchdog_ref_held serialization = add - Configuration
Synchronize watchdog up and watchdog timer operations by using the protections described for netdev_watchdog_up() and dev_watchdog().
Linux kernel netdev watchdog synchronization watchdog_up/watchdog timer synchronization = synchronize - Configuration
Protect netdev_watchdog_up() with tx_global_lock and watchdog_lock (as described: “Protect netdev_watchdog_up() with tx_global_lock and watchdog_lock.”).
Linux kernel netdev watchdog Protection mechanism for netdev_watchdog_up() = tx_global_lock + watchdog_lock - Configuration
In netdev_watchdog_up(), only allocate a new tracker (dev->watchdog_dev_tracker) if one is not already present (as described: “Only allocate a new tracker in netdev_watchdog_up() if one is not already present.”).
Linux kernel netdev watchdog tracker allocation/refcount tracking Tracker allocation in netdev_watchdog_up() = only allocate new tracker if one is not already present - Compensating control
Ensure the updated netdev watchdog code path does not allow concurrent list/refcount corruption by applying the described synchronization (watchdog_lock, tx_global_lock) so netdev_watchdog_up() is only called from process/BH context as stated (“This ensures netdev_watchdog_up() is only called from process/BH context”).