CVE-2018-8897
2018-05-09 03:56 pmТот факт, что инструкции MOV SS и POP SS в интеловских процессорах ведут себя очень необычно, известен давно. Изначальный замысел разработчиков микроархитектуры 8086 был в том, чтобы вслед за одной из этих инструкций всегда следовала инструкция модификации регистра SP, и таким способом в те времена можно было атомарно проинициализировать пару регистров SS:SP, не запрещая прерывания инструкцией CLI и не опасаясь NMI, против которого CLI всё равно не поможет. Для этого в интеловскую микроархитектуру было заложенно хитрое правило: запрос на прерывание, поступивший во время выполнения инструкции MOV SS или POP SS, всегда откладывается до окончания выполнения следующей инструкции (какой бы она ни была).
Позже в системе команд процессора Intel 80386 появилась новая инструкция LSS, умеющая инициализировать пару регистров SS:SP "одним махом", и все эти извращения с одноинструкционным затмением на обработку прерываний после MOV/POP SS стали не нужны. Но, видимо, для совместимости с ранними версиями DOS и BIOS, они остались. До сих пор. И, судя по Intel'овским отчётам о схемотехнических ошибках в процессорах (CPU Errata), это древнее правило из 16-битной эпохи до сих пор доставляет массу неудобств разработчикам микрокода и не только. То ли по недосмотру, то ли по каким-то другим причинам его даже втащили в архитектуру AMD64.
И совсем недавно эту "особенность" таки смогли проэксплуатировать. Nick Peterson из Everdox Tech LLC придумал хитрый приёмчик: если настроить отладку так, чтобы сама инструкция MOV SS вызывала отладочное прерывание (например, прямо перед ней включить Trap Flag), а следующей инструкцией войти в режим ядра (SYSCALL / SYSENTER / INT 2Eh / INT 80h), тогда обработчик отладочного события будет вызван уже в режиме ядра.
Сам обработчик отладочных событий (INT 3) — это всегда код ядра, но вызывается он по-разному, в зависимости от того, откуда пришло прерывание (из юзерспейса или из ядра). Вызов этого обработчика из юзерспейса обходится дороже, т.к. при этом происходит переключение на отдельный стек, настройка регистров FS/GS, выполняется вся эта новая дорогостоящая ерунда для очистки процессорного кэша в связи с уязвимостями Meltdown/Spectre и т.д. До сих пор считалось, что для вызовов INT 3 из ядра можно этого всего не делать — ведь раз мы отладочно трапнулись уже в ядре, значит FS/GS и стек для нас кто-то уже настроил раньше, и кэши почистил тоже. Увы, практика показывает, что это не так. На первой инструкции обработчика SYSCALL / SYSENTER / INT 2Eh / INT 80h стек ещё не переключен, FS/GS ещё не настроены и PTI-шные костыли тоже ещё не задействованы.
Так что теперь отладочные трапы даже из ядра в ядро у Интеля резко "подорожали" из-за того, что их обработчик должен быть готов к новым неожиданностям. Попутно отмечу, что почему-то CVE-2018-8897 для Linux и FreeBSD — это всего лишь Denial-of-Service вследствие kernel panic, а под виндой та же самая уязвимость влечёт возможность исполнения произвольного кода в режиме ядра.
Теперь ждём результатов творческого скрещивания MOV/POS SS с SYSRET / SYSEXIT, IRET, инструкциями VMENTER/VMEXIT, инструкциями входа в SMM, делением на ноль, FPU-исключениями, LOCK-инструкциями, CMPXCHG16B, MONITOR/MWAIT, double fault инструкциями, с новыми инструкциями для борьбы с Meltdown/Spectre (IBPB/STIBP/IBRS), с инструкциями для обновления микрокода и всем остальным грёбанным интеловским зоопарком. Начать можно с циклического исполнения в юзерспейсе длинных страниц, забитых инструкциями MOV SS, AX.
Позже в системе команд процессора Intel 80386 появилась новая инструкция LSS, умеющая инициализировать пару регистров SS:SP "одним махом", и все эти извращения с одноинструкционным затмением на обработку прерываний после MOV/POP SS стали не нужны. Но, видимо, для совместимости с ранними версиями DOS и BIOS, они остались. До сих пор. И, судя по Intel'овским отчётам о схемотехнических ошибках в процессорах (CPU Errata), это древнее правило из 16-битной эпохи до сих пор доставляет массу неудобств разработчикам микрокода и не только. То ли по недосмотру, то ли по каким-то другим причинам его даже втащили в архитектуру AMD64.
И совсем недавно эту "особенность" таки смогли проэксплуатировать. Nick Peterson из Everdox Tech LLC придумал хитрый приёмчик: если настроить отладку так, чтобы сама инструкция MOV SS вызывала отладочное прерывание (например, прямо перед ней включить Trap Flag), а следующей инструкцией войти в режим ядра (SYSCALL / SYSENTER / INT 2Eh / INT 80h), тогда обработчик отладочного события будет вызван уже в режиме ядра.
Сам обработчик отладочных событий (INT 3) — это всегда код ядра, но вызывается он по-разному, в зависимости от того, откуда пришло прерывание (из юзерспейса или из ядра). Вызов этого обработчика из юзерспейса обходится дороже, т.к. при этом происходит переключение на отдельный стек, настройка регистров FS/GS, выполняется вся эта новая дорогостоящая ерунда для очистки процессорного кэша в связи с уязвимостями Meltdown/Spectre и т.д. До сих пор считалось, что для вызовов INT 3 из ядра можно этого всего не делать — ведь раз мы отладочно трапнулись уже в ядре, значит FS/GS и стек для нас кто-то уже настроил раньше, и кэши почистил тоже. Увы, практика показывает, что это не так. На первой инструкции обработчика SYSCALL / SYSENTER / INT 2Eh / INT 80h стек ещё не переключен, FS/GS ещё не настроены и PTI-шные костыли тоже ещё не задействованы.
Так что теперь отладочные трапы даже из ядра в ядро у Интеля резко "подорожали" из-за того, что их обработчик должен быть готов к новым неожиданностям. Попутно отмечу, что почему-то CVE-2018-8897 для Linux и FreeBSD — это всего лишь Denial-of-Service вследствие kernel panic, а под виндой та же самая уязвимость влечёт возможность исполнения произвольного кода в режиме ядра.
Теперь ждём результатов творческого скрещивания MOV/POS SS с SYSRET / SYSEXIT, IRET, инструкциями VMENTER/VMEXIT, инструкциями входа в SMM, делением на ноль, FPU-исключениями, LOCK-инструкциями, CMPXCHG16B, MONITOR/MWAIT, double fault инструкциями, с новыми инструкциями для борьбы с Meltdown/Spectre (IBPB/STIBP/IBRS), с инструкциями для обновления микрокода и всем остальным грёбанным интеловским зоопарком. Начать можно с циклического исполнения в юзерспейсе длинных страниц, забитых инструкциями MOV SS, AX.