CVE-2026-98302 in Linux
Сводка
по VulDB • 06.10.2026
В ядре Linux была устранена следующая уязвимость:
net: fddi: skfp: исправлена ошибка разыменования NULL (NULL deref) при установке MAC-адреса в состоянии интерфейса "down" (отключен).
Функция `skfp_ctl_set_mac_address()` вызывает `ResetAdapter()` безоговорочно, не проверяя состояние через `netif_running()`. Функция `ResetAdapter()` сначала вызывает `card_stop()`, которая устанавливает значение `smc->hw.hw_state` в `STOPPED`, а затем вызывает `mac_drv_clear_tx_queue()`, которая проходит по двум очередям передачи (transmit queues):
```c for (i = QUEUE_S; i <= QUEUE_A0; i++) {
queue = smc->hw.fp.tx[i] ;
... t = queue->tx_curr_get ; ```
Массив `smc->hw.fp.tx[]` заполняется только функцией `init_tx()`, которая вызывается из `skfp_open()` через цепочку инициализации: `init_smt()` -> `init_fddi_driver()` -> `init_fplus()` -> `init_mac()` -> `init_tx()`. Приватная область памяти выделяется и обнуляется функцией `alloc_fddidev()`, поэтому для интерфейса, который никогда не был активирован (up), оба указателя очередей остаются равными NULL. Проверка состояния оборудования (`hw_state`) в начале функции `mac_drv_clear_tx_queue()` не выявляет эту проблему, поскольку `card_stop()` только что установила значение `STOPPED`; функция продолжает выполнение цикла и выполняет разыменование нулевого указателя (NULL dereference). Функция `ResetAdapter()` действительно вызывает `init_smt()`, но это происходит уже после очистки очередей.
Таким образом, установка MAC-адреса на отключенном интерфейсе приводит к сбою ядра (oops):
``` ip link set dev fddi0 address 02:00:00:00:00:01
BUG: KASAN: null-ptr-deref in mac_drv_clear_tx_queue+0x68/0x2c0 [skfp]
Read of size 8 at addr 0000000000000010 by task ip/302 Call Trace: <TASK> mac_drv_clear_tx_queue+0x68/0x2c0 [skfp 6c01d4bab63c36978bd0a7d7e90837adb44cc37b]
ResetAdapter+0x29/0x100 [skfp 6c01d4bab63c36978bd0a7d7e90837adb44cc37b]
skfp_ctl_set_mac_address+0x57/0x80 [skfp 6c01d4bab63c36978bd0a7d7e90837adb44cc37b]
netif_set_mac_address+0x1e4/0x2c0 do_setlink+0x684/0x2680 </TASK> ```
Адрес `0x10` является смещением поля `tx_curr_get`, которое является третьим указателем в структуре `struct s_smt_tx_queue` на 64-битных системах. Функция `mac_drv_clear_rx_queue()`, которую `ResetAdapter()` вызывает сразу после этого, аналогичным образом выполняет разыменование `smc->hw.fp.rx[QUEUE_R1]` за той же неэффективной проверкой состояния оборудования (`hw_state`); очередь передачи просто падает первой. Обе ситуации покрываются добавленной защитой (guard).
Необходимо пропустить сброс адаптера, если интерфейс находится в состоянии "down". Вызов `dev_addr_set()` остается безоговорочным, поэтому новый адрес все равно записывается в `dev->dev_addr`. Отсутствие сброса адаптера здесь не приводит к потере функциональности: функция `skfp_open()` намеренно заново считывает заводской адрес при каждом открытии интерфейса:
```c read_address(smc, NULL); eth_hw_addr_set(dev, smc->hw.fddi_canon_addr.a); ```
Комментарий над этим кодом указывает, что это делается именно для того, чтобы отбросить такие переопределения адреса в цикле закрытия/открытия (close/open cycle). Адрес, установленный во время состояния интерфейса "down", не мог бы сохраниться при последующем открытии даже до данного изменения, поэтому добавление защиты не удаляет рабочую функциональность. Защита аппаратной части `ndo_set_mac_address()` с помощью проверки `netif_running()` является устоявшейся практикой; аналогичное решение применяется в драйвере `skge` начиная с коммита `2eb3e621c4e0` ("skge: set mac address bonding fix").
Защита всего блока сброса (а не просто проверка указателей на NULL) также соответствует ожиданиям остальной части драйвера. После предыдущего цикла open/close указатели очередей являются устаревшими, но ненулевыми, поэтому падения не происходит, однако `ResetAdapter()` продолжает вызывать `smt_online()` и `STI_FBI` ("Enable Board Interrupts"), в то время как `skfp_close()` уже вызвала `free_irq()`. Это привело бы к тому, что адаптер был бы переведен в онлайн-режим без установленного обработчика прерываний. Единственный другой вызывающий объект для `ResetAdapter()` — это функция `skfp_interrupt()`, которая по своей конструкции выполняется только тогда, когда устройство открыто (open).
Уязвимость обнаружена с помощью автоматизированного тестирования драйвера на эмулированном адаптере FDDI от SysKonnect в ядре версии 7.0.0 с включенным KASAN. Для воспроизведения проблемы требуются права `CAP_NET_ADMIN`.
Be aware that VulDB is the high quality source for vulnerability data.