Домас взломал синхронизацию SMM x86-процессоров одной сверхдолгой инструкцией

Исследователь безопасности Кристофер Домас (Christopher Domas, известен под ником @xoreaxeaxeax) опубликовал на GitHub proof-of-concept инструмент smiiiiiiiiiiiiiiii, который ломает базовое допущение защиты System Management Mode (SMM), сверхпривилегированного режима выполнения, незаметно работающего в фоне на каждом x86-процессоре. Безопасность SMM держится на одном правиле: когда одно ядро получает сигнал войти в SMM (SMI), прошивка заставляет войти в SMM абсолютно все ядра одновременно, иначе одно ядро могло бы вмешаться в работу другого, пока то выполняет привилегированный код. Чтобы это гарантировать, прошивка при входе в SMM ждёт, пока присоединятся все ядра, но не дольше 1 секунды, таков тайм-аут рандеву (общей точки сбора ядер).
Домас показал: если заставить одно ядро выполнять единственную машинную инструкцию длиной около 4 миллиардов тактов (это более 1 секунды по времени), прошивка не дождётся его и «сдастся», остальные ядра войдут в SMM без него. Это ядро остаётся снаружи SMM и может атаковать остальные ядра, пока те внутри режима, который по определению должен быть неприкасаемым. Механизм работает из-за того, что SMI прерывает ядро только на границе между инструкциями: любой промежуток между двумя инструкциями впустил бы ожидающий SMI и затянул ядро в SMM, поэтому единственный способ продержаться весь тайм-аут, это одна инструкция, которая сама по себе длится дольше секунды.
Чтобы получить настолько медленную инструкцию на реальном железе, PoC ищет область памяти с отображением ввода-вывода (MMIO), отвечающую на чтение крайне медленно, и читает из неё максимально широкой загрузкой, какую допускает набор инструкций процессора. Готовый вариант в репозитории настроен под конкретную машину, AMD Ryzen 7 5800H (Zen 3): широкое чтение регистра xmm по адресу 0xfcc68860 стабильно стопорится дольше секунды. Одно ядро в цикле крутит эту медленную загрузку, изображая «слишком занятое, чтобы среагировать на SMI». Второе ядро тем временем настраивает аппаратные счётчики производительности AMD (регистры MSR 0xc0010200 и 0xc0010201) на подсчёт SMI по каждому ядру отдельно, затем через порт ввода-вывода 0xb2 программно вызывает шторм прерываний SMI и сравнивает итоговые счётчики всех ядер. Если счётчики разошлись, значит, одно ядро пропустило часть SMI, то есть оставалось снаружи SMM, пока остальные были внутри; именно это и подтверждает, что синхронизация сломана.
По словам автора, это важно потому, что снимает главное препятствие для целого класса дремлющих уязвимостей: в SMM-обработчиках существует более 100 известных TOCTOU-багов (race condition между проверкой значения в разделяемой памяти и его последующим использованием), обработчик проверяет значение, а использует его позже, и если значение подменить между проверкой и использованием, можно выполнить код внутри SMM. До сих пор эти баги считались практически неопасными и оставались без патчей, потому что подменить значение в момент, когда SMM выполняется, было некому: единственный теоретический путь, DMA-устройство, пишущее в память в обход процессора, то есть требовался физический доступ и вредоносное железо. Рассинхронизация SMI убирает это требование: обычное процессорное ядро без SMM и без физического доступа к машине может теперь играть роль такого атакующего, и спящие уязвимости становятся эксплуатируемыми чисто программно.
Автор не даёт готового решения проблемы и открыто описывает дилемму: оставить тайм-аут рандеву как есть, синхронизацию по-прежнему легко сломать; убрать тайм-аут вовсе, платформа зависнет при первом же SMI, если ядро застряло по легитимной причине; увеличить тайм-аут, упадёт производительность многоядерных систем, которым и так приходится останавливать все ядра при каждом входе в SMM. По словам Домаса, неясно, есть ли вообще правильный путь вперёд; до его появления рекомендованный обходной путь, не допускать выполнения сверхдолгих инструкций. Он также отдельно оговаривает, что настройки PoC по умолчанию (адрес 0xfcc68860), медленное место именно на его тестовой машине Zen 3 Ryzen 7 5800H и, вероятно, больше нигде; на любом другом процессоре расхождения счётчиков не будет, пока пользователь сам не подберёт под своё железо медленную область MMIO, не расширит ширину чтения (xmm → ymm → zmm) или не найдёт другую аномально долгую инструкцию.
Ключевые факты
- Кристофер Домас (@xoreaxeaxeax) опубликовал PoC-инструмент smiiiiiiiiiiiiiiii, который ломает синхронный вход всех ядер x86-процессора в SMM.
- Один прогон одной машинной инструкции длиной около 4 млрд тактов (более 1 секунды) не даёт ядру уложиться в тайм-аут рандеву SMM (1 секунда), и прошивка входит в SMM без него.
- SMI прерывает ядро только на границе инструкций, поэтому единственная сверхдолгая инструкция, единственный способ продержать ядро снаружи SMM весь тайм-аут.
- Это снимает физическое требование (DMA-устройство с физическим доступом) для эксплуатации более 100 известных, но дремлющих SMM TOCTOU-уязвимостей, они становятся доступны чисто программно.
- Готового решения нет: любой вариант с тайм-аутом рандеву, оставить, убрать или увеличить, либо оставляет дыру, либо вешает систему, либо бьёт по производительности многоядерных платформ.
Почему это важно
SMM в x86-процессорах существует именно как режим, в котором гарантированно ничего постороннего не выполняется, пока он активен, на этом допущении держится вся его модель безопасности. Домас показал, что это допущение можно нарушить программно: единственная аномально долгая инструкция выбивает одно ядро из общего рандеву, и оно остаётся снаружи SMM, пока остальные внутри. Это не единичный баг в конкретном обработчике, а брешь в самом механизме синхронизации, на который опираются все SMM-обработчики сразу.
Кому это важно
В первую очередь это касается производителей процессоров и разработчиков прошивки (UEFI/BIOS), которым предстоит решать, что делать с тайм-аутом рандеву SMM. Дальше, исследователей безопасности и владельцев более 100 известных SMM TOCTOU-уязвимостей: то, что раньше считалось непрактичным без физического доступа к железу, теперь стоит переоценить как программно эксплуатируемое. Также это релевантно операторам многоядерных серверных и облачных платформ на x86, для которых любое ужесточение SMM-синхронизации напрямую бьёт по производительности.
Как это применить
Инструмент и код опубликованы на GitHub под именем smiiiiiiiiiiiiiiii; PoC по умолчанию настроен под одну конкретную машину, AMD Ryzen 7 5800H (Zen 3) с медленной MMIO-областью по адресу 0xfcc68860. Чтобы воспроизвести эффект на другом процессоре, автор советует найти собственную медленную MMIO-область на своей платформе, при необходимости расширить чтение с xmm до ymm или zmm, либо подобрать другую аномально долгую инструкцию, если ни одно чтение MMIO не оказывается достаточно медленным.
Можно ли доверять
Материал, прямой технический отчёт автора эксплойта с исходным кодом, ассемблерными фрагментами и объяснением механизма на уровне прошивки, что делает его достоверным как техническое описание находки. При этом источник сам оговаривает границы: он не называет производителя, подтвердившего или исправившего проблему, не приводит идентификаторов CVE для упомянутых более 100 SMM TOCTOU-уязвимостей и не утверждает, что какая-либо из них уже реально эксплуатировалась этим способом, речь идёт о том, что они становятся эксплуатируемыми в принципе, а не о зафиксированных атаках. Дата публикации в источнике не указана.
Риски и подводные камни
PoC воспроизводится «из коробки» только на одной протестированной машине (AMD Zen 3 Ryzen 7 5800H), на любом другом процессоре для повторения эффекта нужно вручную подбирать медленную MMIO-область и ширину чтения. У проблемы нет очевидного исправления: сохранить тайм-аут рандеву, оставить синхронизацию легко ломаемой; убрать тайм-аут, рискнуть зависанием всей платформы, если какое-то ядро застрянет по обычной, не вредоносной причине; увеличить тайм-аут, заплатить производительностью на многоядерных системах, которым и так приходится приостанавливать все ядра при каждом входе в SMM. Пока рекомендованный автором обходной путь, не допускать выполнения аномально долгих инструкций, что не устраняет саму брешь в модели синхронизации.