CVE-2026-81001: slip: fix use-after-free in sl_sync()
In the Linux kernel, the following vulnerability has been resolved:
slip: fix use-after-free in slsync()
slipdevs[] stores bare netdevice pointers and takes no reference on them. slsync() and slalloc() walk that table from slipopen() under rtnllock(), while an entry is dropped by slfreenetdev(), which slsetup() installs as dev->privdestructor.
privdestructor is called from netdevruntodo(), which deliberately runs with the RTNL semaphore released so that it can sleep while waiting for the device refcount to drop:
/ Snapshot list, allow later requests / listreplaceinit(&nettodolist, &list);
rtnlunlock(); ... if (dev->privdestructor) dev->privdestructor(dev); / slipdevs[i] = NULL / if (dev->needsfreenetdev) freenetdev(dev); ... / Free network device / kobjectput(&dev->dev.kobj);
So rtnllock() does not serialise slipopen() against the teardown at all. slsync() can load slipdevs[i] while the entry is still published and dereference it after netdevruntodo() has run the destructor and released the device:
CPU0 (slipopen) CPU1 (slipclose) unregisternetdev() rtnlunlock() netdevruntodo() rtnlunlock() rtnllock() slsync() dev = slipdevs[i] privdestructor(dev) slipdevs[i] = NULL kobjectput(&dev->dev.kobj) / dev is freed / sl = netdevpriv(dev) if (sl->tty || sl->leased) / use-after-free /
BUG: KASAN: use-after-free in slsync drivers/net/slip/slip.c:730 [inline] BUG: KASAN: use-after-free in slipopen+0xef4/0x1210 drivers/net/slip/slip.c:806 Read of size 1 at addr ffff8880712dac71 by task syz-executor.2/6506
CPU: 2 PID: 6506 Comm: syz-executor.2 Not tainted 6.1.134-syzkaller-00260-g0c8fc3469765 #0 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 Call Trace: slsync drivers/net/slip/slip.c:730 [inline] slipopen+0xef4/0x1210 drivers/net/slip/slip.c:806 ttyldiscopen+0xa2/0x120 drivers/tty/ttyldisc.c:433 ttysetldisc+0x324/0x720 drivers/tty/ttyldisc.c:564 tiocsetd drivers/tty/ttyio.c:2428 [inline] ttyioctl+0x5f0/0x1530 drivers/tty/ttyio.c:2712
Allocated by task 6502: allocnetdevmqs+0x98/0xfe0 net/core/dev.c:10719 slalloc drivers/net/slip/slip.c:756 [inline] slipopen+0x36d/0x1210 drivers/net/slip/slip.c:817 ttyldiscopen+0xa2/0x120 drivers/tty/ttyldisc.c:433 ttysetldisc+0x324/0x720 drivers/tty/ttyldisc.c:564
Freed by task 6497: devicerelease+0xa2/0x240 drivers/base/core.c:2507 kobjectput+0x179/0x280 lib/kobject.c:729 netdevruntodo+0x6c8/0xef0 net/core/dev.c:10509 slipclose+0x166/0x1c0 drivers/net/slip/slip.c:906 ttyldiscclose+0x113/0x1a0 drivers/tty/ttyldisc.c:456 ttyldisckill+0x94/0x160 drivers/tty/ttyldisc.c:614 ttyldiscrelease+0xe3/0x2b0 drivers/tty/ttyldisc.c:782 ttyrelease+0xbcc/0xe70 drivers/tty/ttyio.c:1860
Commit e58c19124189 ("slip: Fix use-after-free Read in slipopen") fixed a different source of stale entries - a device left in slipdevs[] after slipopen() freed it on the registration error path - and does not address this race, which is why the report survives it.
Drop the entry from ndouninit instead. unregisternetdevice() calls ndouninit under RTNL, before the device is queued to netdevruntodo(), so an entry that slsync() can still see while holding RTNL belongs to a device that cannot be freed until RTNL is dropped. slfreenetdev() stays only for the slipopen() error path, where registernetdevice() may have failed before ndoinit and ndouninit is then not called either. Both running for the same device is harmless: the ---truncated---
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade to a fixed release to a version that resolves this vulnerability.
Patch e58c19124189 - Operational
Reboot or reload the affected Linux kernel/network subsystem after applying commit e58c19124189 so the slip driver is running the fixed code.
Event History
Frequently Asked Questions
What activity is required for the race to occur?
A SLIP device open path must walk the slip_devs[] table while another CPU is closing and unregistering a SLIP device. The vulnerable window exists because teardown can remove and free the device after releasing RTNL while the open path still holds a bare pointer.
Does holding rtnl_lock() protect the SLIP open path from this teardown?
No. netdev_run_todo() deliberately releases RTNL before calling the device private destructor, so sl_sync() or sl_alloc() can run under RTNL concurrently with sl_free_netdev() removing the table entry and freeing the device.