SMM — это защищённый режим x86 с максимальными привилегиями, который работает в фоне незаметно для ОС. Его модель безопасности держится на простом правиле: все ядра CPU либо одновременно внутри SMM, либо снаружи. Когда одно ядро получает SMI, остальные обязаны присоединиться. Оказалось, правило можно сломать одной инструкцией — просто сделать её настолько длинной, что ядро физически не успеет отреагировать на приглашение войти в SMM.
Механика такая: ядро 0 начинает выполнять супер-долгую инструкцию. Ядро 1 получает SMI, входит в SMM и ждёт остальные. Прошивка x86 при входе в SMM запускает цикл синхронизации, который ждёт все ядра до 1 секунды — а потом сдаётся. Если ядро 0 всё ещё занято одной машинной инструкцией, оно не может ответить на SMI, потому что прерывание обрабатывается только на границе инструкций. Через секунду ядро 1 сдаётся, выполняет «секретные» SMM-дела и выходит, а ядро 0 только после этого заходит в SMM. Итог: одно ядро снаружи SMM, одно внутри — патруль разошёлся.
Нужна инструкция, которая молотит около 4 миллиардов циклов — больше секунды. Например, медленное чтение из MMIO. PoC от Кристофера Домаса заточен под Zen 3 Ryzen 7 5800H: там одиночная vmovdqu из адреса 0xfcc68860 через xmm регистр подвисает достаточно долго. Можно расширить загрузку до ymm или zmm, чтобы замедлить ещё сильнее. Пока ядро-жертва крутит цикл с этой инструкцией, второе ядро через порт 0xb2 устраивает шторм SMI и сверяет счётчики MSR_PERF_CTL0 / MSR_PERF_CTR0 на всех ядрах. Если счётчики разошлись — кто-то остался снаружи SMM.
Это превращает кучу «спящих» уязвимостей в реальные атаки. В SMM больше 100 CVEs типа TOCTOU: обработчик проверяет значение в общей памяти, потом использует его. Раньше считалось, что между проверкой и использованием никто не может вмешаться, ведь все CPU внутри SMM, а DMA-устройства требуют физического доступа. Теперь же внешнее ядро может менять память прямо во время работы SMM — без железа и физического доступа.
Для повторения на другой машине надо найти медленную MMIO-область через mmiotic, подобрать ширину чтения xmm → ymm → zmm и, если не помогает, искать патологически длинные инструкции через asm-hall-of-shame. Инструмент называется smiiiiiiiiiiiiiiii, по умолчанию он бьёт чтением xmm по адресу 0xfcc68860 и предупреждает, что на других платформах придётся перенастраивать параметры.