В ядре Linux устранена следующая уязвимость:
Bluetooth: btmtksdio: исправлен бесконечный цикл в btmtksdio_txrx_work(). Время от времени мы видим зависшую задачу btmtksdio_flush():
ИНФОРМАЦИЯ: задача kworker/u17:0:189 заблокирована более чем на 122 секунды.
__cancel_work_timer+0x3f4/0x460
cancel_work_sync+0x1c/0x2c
btmtksdio_flush+0x2c/0x40
hci_dev_open_sync+0x10c4/0x2190
[..]
Все сводится к неправильному использованию time_is_before_jiffies() в
btmtksdio_txrx_work(). Ожидается цикл btmtksdio_txrx_work().
быть прекращено, если работает более 5*HZ.
Однако
проверка таймаута перекручена: time_is_before_jiffies(old_jiffies + 5*HZ)
оценивается как true, когда old_jiffies + 5*HZ находится в прошлом, т.е. когда
произошел тайм-аут. Использование OR с time_is_before_jiffies(txrx_timeout)
означает, что:
- до истечения 5-секундного таймаута: условие `int_status || ложь`,
поэтому он зацикливается до тех пор, пока есть ожидающие прерывания.
- после 5-секундного таймаута: условие становится `int_status || правда`,
что всегда верно. Когда цикл становится бесконечным, цикл btmtksdio_txrx_work() никогда
завершается и никогда не освобождает хост SDIO.
Исправьте условие завершения цикла, чтобы фактически обеспечить тайм-аут 5 * Гц.
Показать оригинальное описание (EN)
In the Linux kernel, the following vulnerability has been resolved: Bluetooth: btmtksdio: fix infinite loop in btmtksdio_txrx_work() Every once in a while we see a hung btmtksdio_flush() task: INFO: task kworker/u17:0:189 blocked for more than 122 seconds. __cancel_work_timer+0x3f4/0x460 cancel_work_sync+0x1c/0x2c btmtksdio_flush+0x2c/0x40 hci_dev_open_sync+0x10c4/0x2190 [..] It all boils down to incorrect time_is_before_jiffies() usage in btmtksdio_txrx_work(). The btmtksdio_txrx_work() loop is expected to be terminated if running for longer than 5*HZ. However the timeout check is twisted: time_is_before_jiffies(old_jiffies + 5*HZ) evaluates to true when old_jiffies + 5*HZ is in the past i.e. when a timeout has occurred. Using OR with time_is_before_jiffies(txrx_timeout) means that: - before the 5-second timeout: the condition is `int_status || false`, so it loops as long as there are pending interrupts. - after the 5-second timeout: the condition becomes `int_status || true`, which is always true. When the loop becomes infinite btmtksdio_txrx_work() loop never terminates and never releases the SDIO host. Fix loop termination condition to actually enforce a 5*HZ timeout.