В ядре Linux устранена следующая уязвимость:
промах: исправлено использование после освобождения в sl_sync()
lip_devs[] хранит голые указатели net_device и не ссылается на них.
их. sl_sync() и sl_alloc() просматривают эту таблицу изlip_open() под
rtnl_lock(), а запись удаляется с помощью sl_free_netdev(), что
sl_setup() устанавливается как dev->priv_destructor.
priv_destructor вызывается из netdev_run_todo(), что намеренно
работает с освобожденным семафором RTNL, чтобы он мог спать во время ожидания
чтобы счетчик ссылок устройства был удален:
/* Список снимков, разрешить последующие запросы */
list_replace_init(&net_todo_list, &list);
__rtnl_unlock();
...
если (dev->priv_destructor)
dev->priv_destructor(dev); /*lip_devs[i] = NULL */
если (dev->needs_free_netdev)
free_netdev (Дев);
...
/* Свободное сетевое устройство */
kobject_put(&dev->dev.kobj);
Таким образом, rtnl_lock() не сериализуетlip_open() при демонтаже в
все. sl_sync() может загрузитьlip_devs[i], пока запись еще опубликована
и разыменовать его после того, как netdev_run_todo() запустит деструктор и
выпустил устройство:
CPU0 (slip_open) CPU1 (slip_close)
unregister_netdev()
rtnl_unlock()
netdev_run_todo()
__rtnl_unlock()
rtnl_lock()
sl_sync()
dev =lip_devs[i]
priv_destructor (дев)
lip_devs[i] = NULL
kobject_put(&dev->dev.kobj)
/* разработчик освобожден */
sl = netdev_priv(dev)
if (sl->tty || sl->leased) /* использование после освобождения */
ОШИБКА: KASAN: использование после освобождения в sl_sync driver/net/slip/slip.c:730 [inline]
ОШИБКА: KASAN: use-after-free в slot_open+0xef4/0x1210 driver/net/slip/slip.c:806
Чтение размера 1 по адресу ffff8880712dac71 с помощью задачи syz-executor.2/6506. ЦП: 2 PID: 6506 Связь: syz-executor.2 Не испорчен 6.1.134-syzkaller-00260-g0c8fc3469765 #0
Название оборудования: QEMU Standard PC (i440FX + PIIX, 1996 г.), BIOS 1.12.0-1 от 01.04.2014 г. Отслеживание вызова:
sl_sync driver/net/slip/slip.c:730 [встроенный]
lip_open+0xef4/0x1210 driver/net/slip/slip.c:806
tty_ldisc_open+0xa2/0x120 драйверы/tty/tty_ldisc.c:433
tty_set_ldisc+0x324/0x720 драйверы/tty/tty_ldisc.c:564
tiocsetd driver/tty/tty_io.c:2428 [встроенный]
tty_ioctl+0x5f0/0x1530 драйверы/tty/tty_io.c:2712
Выделено задачей 6502:
alloc_netdev_mqs+0x98/0xfe0 net/core/dev.c:10719
sl_alloc driver/net/slip/slip.c:756 [встроенный]
lip_open+0x36d/0x1210 driver/net/slip/slip.c:817
tty_ldisc_open+0xa2/0x120 драйверы/tty/tty_ldisc.c:433
tty_set_ldisc+0x324/0x720 драйверы/tty/tty_ldisc.c:564
Освобожден заданием 6497:
device_release+0xa2/0x240 драйверы/base/core.c:2507
kobject_put+0x179/0x280 lib/kobject.c:729
netdev_run_todo+0x6c8/0xef0 net/core/dev.c:10509
lip_close+0x166/0x1c0 driver/net/slip/slip.c:906
tty_ldisc_close+0x113/0x1a0 драйверы/tty/tty_ldisc.c:456
tty_ldisc_kill+0x94/0x160 драйверы/tty/tty_ldisc.c:614
tty_ldisc_release+0xe3/0x2b0 драйверы/tty/tty_ldisc.c:782
tty_release+0xbcc/0xe70 драйверы/tty/tty_io.c:1860
Коммит e58c19124189 («slip: Fix use-after-free Read inlip_open») исправлен.
другой источник устаревших записей — устройство осталось вlip_devs[] после
lip_open() освободил его на пути ошибки регистрации - и не
обратиться к этой гонке, и именно поэтому отчет сохранился.
Вместо этого удалите запись из ndo_uninit. вызовы unregister_netdevice()
ndo_uninit под RTNL, прежде чем устройство будет поставлено в очередь на netdev_run_todo(),
поэтому запись, которую sl_sync() может видеть, удерживая RTNL, принадлежит
устройство, которое нельзя освободить, пока не будет отключен RTNL. sl_free_netdev()
остается только для пути ошибкиlip_open(), где Register_netdevice()
возможно, произошла ошибка до того, как ndo_init и ndo_uninit не будут вызываться
либо. Оба запуска на одном и том же устройстве безвредны:
---усечено---
Показать оригинальное описание (EN)
In the Linux kernel, the following vulnerability has been resolved: slip: fix use-after-free in sl_sync() slip_devs[] stores bare net_device pointers and takes no reference on them. sl_sync() and sl_alloc() walk that table from slip_open() under rtnl_lock(), while an entry is dropped by sl_free_netdev(), which sl_setup() installs as dev->priv_destructor. priv_destructor is called from netdev_run_todo(), 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 */ list_replace_init(&net_todo_list, &list); __rtnl_unlock(); ... if (dev->priv_destructor) dev->priv_destructor(dev); /* slip_devs[i] = NULL */ if (dev->needs_free_netdev) free_netdev(dev); ... /* Free network device */ kobject_put(&dev->dev.kobj); So rtnl_lock() does not serialise slip_open() against the teardown at all. sl_sync() can load slip_devs[i] while the entry is still published and dereference it after netdev_run_todo() has run the destructor and released the device: CPU0 (slip_open) CPU1 (slip_close) unregister_netdev() rtnl_unlock() netdev_run_todo() __rtnl_unlock() rtnl_lock() sl_sync() dev = slip_devs[i] priv_destructor(dev) slip_devs[i] = NULL kobject_put(&dev->dev.kobj) /* dev is freed */ sl = netdev_priv(dev) if (sl->tty || sl->leased) /* use-after-free */ BUG: KASAN: use-after-free in sl_sync drivers/net/slip/slip.c:730 [inline] BUG: KASAN: use-after-free in slip_open+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: sl_sync drivers/net/slip/slip.c:730 [inline] slip_open+0xef4/0x1210 drivers/net/slip/slip.c:806 tty_ldisc_open+0xa2/0x120 drivers/tty/tty_ldisc.c:433 tty_set_ldisc+0x324/0x720 drivers/tty/tty_ldisc.c:564 tiocsetd drivers/tty/tty_io.c:2428 [inline] tty_ioctl+0x5f0/0x1530 drivers/tty/tty_io.c:2712 Allocated by task 6502: alloc_netdev_mqs+0x98/0xfe0 net/core/dev.c:10719 sl_alloc drivers/net/slip/slip.c:756 [inline] slip_open+0x36d/0x1210 drivers/net/slip/slip.c:817 tty_ldisc_open+0xa2/0x120 drivers/tty/tty_ldisc.c:433 tty_set_ldisc+0x324/0x720 drivers/tty/tty_ldisc.c:564 Freed by task 6497: device_release+0xa2/0x240 drivers/base/core.c:2507 kobject_put+0x179/0x280 lib/kobject.c:729 netdev_run_todo+0x6c8/0xef0 net/core/dev.c:10509 slip_close+0x166/0x1c0 drivers/net/slip/slip.c:906 tty_ldisc_close+0x113/0x1a0 drivers/tty/tty_ldisc.c:456 tty_ldisc_kill+0x94/0x160 drivers/tty/tty_ldisc.c:614 tty_ldisc_release+0xe3/0x2b0 drivers/tty/tty_ldisc.c:782 tty_release+0xbcc/0xe70 drivers/tty/tty_io.c:1860 Commit e58c19124189 ("slip: Fix use-after-free Read in slip_open") fixed a different source of stale entries - a device left in slip_devs[] after slip_open() freed it on the registration error path - and does not address this race, which is why the report survives it. Drop the entry from ndo_uninit instead. unregister_netdevice() calls ndo_uninit under RTNL, before the device is queued to netdev_run_todo(), so an entry that sl_sync() can still see while holding RTNL belongs to a device that cannot be freed until RTNL is dropped. sl_free_netdev() stays only for the slip_open() error path, where register_netdevice() may have failed before ndo_init and ndo_uninit is then not called either. Both running for the same device is harmless: the ---truncated---
Характеристики атаки
Последствия
Строка CVSS v3.1