Пять лет в тени, миллионы пользователей в зоне риска. Intel раскрыл критический баг в ядре Linux

Патч уже в 6.19 и пойдет в бэкпорты, чтобы прерывания выключались правильно во всех сценариях.


jfytkes1mylo9tx6uoav689cdp06k5x1.jpg

В ядре Linux снова нашли баг, который годами сидел в одном из самых чувствительных мест системы: обработке page fault на x86. Это тот самый момент, когда процессор внезапно понимает, что программа полезла в память, к которой сейчас нет корректного доступа, и ядро должно быстро и аккуратно разобраться, что делать дальше. И вот выяснилось, что с 2020 года в этой логике была тонкая, но принципиальная ошибка: прерывания отключались не всегда так, как предполагалось.

Исправление уже приняли в ветку Linux 6.19, а дальше его планируют портировать и в более старые стабильные серии. Инициатором стал инженер Intel Седрик Синь (Cedric Xing), который раскопал проблему в коде обработки исключения page fault и предложил простой, но более надежный подход.

Суть истории упирается в старый комментарий внутри функции do_page_fault() для x86. Там много лет объяснялось, что при обработке ошибок доступа к памяти прерывания могли быть повторно включены, особенно в сценариях с ошибками на пользовательских адресах. При этом прямо признавалось, что пройтись по всем возможным веткам выхода и гарантировать правильное состояние прерываний в каждом месте почти нереально: получится либо «адский» комбинаторный ремонт, либо переворот логики с ног на голову.

Но, как выяснилось, этот комментарий был немного неправильным, а вместе с ним неправильной была и логика вокруг него. Проблема не ограничивалась «ошибками на пользовательских адресах». В обработчике смешались две разные идеи: диапазон адреса (пользовательский или ядра) и контекст, в котором был выполнен доступ (условно, пользовательский сценарий или ядровой). Эти вещи связаны интуитивно, но на практике не равны. Бывают ситуации, когда обращение к адресам ядра происходит в пользовательском контексте, и тогда отдельные ветки обработки способны включить прерывания, хотя на выходе они должны быть снова выключены, прежде чем управление вернется в низкоуровневый обработчик исключения.