Как BTR похищает память Linux через уже удалённый JIT-код?

Исследователи VUSec и Scuola Superiore Sant'Anna раскрыли Branch Target Reuse, или BTR, новый вариант Spectre v2. Атака затрагивает JIT-движки браузеров, языковые среды выполнения и ядра операционных систем на процессорах разных производителей. Она позволяет непривилегированному коду добраться до конфиденциальной памяти даже при включённых средствах защиты от Spectre. Работу подготовили Сандер Вибинг (Sander Wiebing), Юйхуэй Чжу (Yuhui Zhu), Алессандро Бионди (Alessandro Biondi) и Кристиано Джуффрида (Cristiano Giuffrida).
Как BTR похищает память Linux через уже удалённый JIT-код?
Изображение носит иллюстративный характер

В основе BTR лежит рассинхронизация двух уровней работы процессора. Когда самомодифицирующийся код, или SMC, заменяет исполняемые инструкции, процессор восстанавливает их обычную архитектурную когерентность: программа видит уже новый код. Но старые сведения, которыми пользуется механизм предсказания косвенных переходов, могут сохраниться. В частности, устаревшая запись остаётся в Branch Target Buffer, сокращённо BTB, где процессор хранит предполагаемые адреса переходов. Получается неприятная ситуация: на архитектурном уровне прежнего фрагмента кода уже нет, а микроархитектурный предсказатель всё ещё помнит путь к нему.
JIT-компиляторы генерируют машинный код прямо во время работы программы, удаляют ставшие ненужными блоки и заново занимают освободившиеся участки кэша кода. Если вместе с удалённым блоком не исчезла соответствующая запись BTB, процессор позднее может использовать её для другого блока, размещённого по тому же или частично совпадающему адресу. Авторы назвали этот механизм «примитивом кратковременного исполнения после освобождения». По их данным, это первый показанный на практике способ получить пригодное для атаки кратковременное исполнение в JIT-среде именно из-за самомодифицирующегося кода.
Сценарий начинается с тренировочного блока JIT-кода. Злоумышленник многократно выполняет косвенный переход и приучает предсказатель связывать его с определённой точкой входа. Затем JIT освобождает тренировочный блок, после чего целевой блок частично занимает тот же адресный диапазон. При новом косвенном переходе процессор обращается к устаревшей записи BTB и спекулятивно прыгает по прежнему смещению. Теперь там могут находиться новые инструкции либо последовательность, прочитанная с неверной границы. Так появляются несогласованные по адресу гаджеты, способные обойти программное усиление защиты от Spectre и обратиться к секретным данным.
Ошибочный путь существует недолго. Обнаружив неверное предсказание, процессор отменяет архитектурные результаты: регистры и видимое состояние программы возвращаются к правильному варианту. Изменения кэша при этом сохраняются. Злоумышленник измеряет время доступа к разным участкам памяти и по разнице задержек выясняет, какие данные успело обработать спекулятивное исполнение. Этот cache-timing side channel, то есть побочный канал по времени доступа к кэшу, превращает кратковременный перехват потока управления в утечку. Для успеха нужны два условия: старая запись BTB должна пережить освобождение тренировочного блока, а предсказатель впоследствии должен выбрать именно её.
BTR проверили в трёх крупных средах. Первая — SpiderMonkey, JIT-движок Mozilla Firefox. Вторая — GraalVM, языковая среда выполнения и платформа JIT-компиляции. Третья — cBPF JIT в ядре Linux, компилятор для classic Berkeley Packet Filter. Все три оказались затронуты, хотя пригодность для эксплуатации и скорость утечки заметно различались. Такая разница закономерна: JIT-системы по-разному распределяют память, освобождают блоки, повторно используют адреса и формируют машинные инструкции. Само присутствие уязвимого механизма ещё не даёт одинаковой атаки для браузера, виртуальной машины и ядра.
Для Linux исследователи собрали два полноценных доказательства возможности эксплуатации. Они извлекали память ядра и восстанавливали хеш пароля root за несколько минут. Опыты прошли на полностью обновлённой системе с процессором Intel, при этом стандартные защитные механизмы оставались включёнными. Речь шла не о теоретическом гаджете и не об отключённой ради эксперимента защите: цепочка доходила до получения чувствительных данных. Тем самым BTR обходит часть программных мер против Spectre v2 за счёт состояния предсказателя, которое существует отдельно от корректно обновлённого исполняемого кода.
Класс Spectre известен с 2017 года и связан со спекулятивным исполнением. Ради скорости процессор заранее выполняет инструкции, которые, по его прогнозу, скоро понадобятся. Spectre v2 атакует предсказание косвенных переходов: злоумышленник заставляет процессор выбрать нужную ему цель, после чего тот временно выполняет гаджет — подходящую последовательность инструкций. Обычные варианты Spectre v2 активно «отравляют» предсказатель. BTR устроен тоньше: атака повторно использует уже существующую, но устаревшую цель после удаления и замены JIT-кода. Процессор правильно видит новые инструкции, однако продолжает предсказывать переход по старой карте.
GraalVM затрудняет эксплуатацию с помощью рандомизации адресов JIT-кэша. Из-за этого злоумышленнику сложнее добиться предсказуемого повторного занятия нужного участка памяти, хотя полного устранения BTR исследование не заявляет. Mozilla рассматривала защиту на основе IBPB, Indirect Branch Predictor Barrier. Этот барьер предназначен для очистки либо изоляции состояния предсказателя косвенных переходов. Сейчас Mozilla отдаёт приоритет завершению и развёртыванию изоляции сайтов: веб-сайты разносятся по более жёстко разделённым средам исполнения, что сокращает возможности межсайтовой утечки, но решает задачу на другом уровне.
Раскрытие BTR последовало почти через два месяца после сообщения о другой атаке на спекулятивное исполнение — Interrupt Injection. Её разработали Даниэль Трухильо (Daniël Trujillo) и Мэнцзя Янь (Mengjia Yan) из MIT CSAIL, Лаборатории компьютерных наук и искусственного интеллекта Массачусетского технологического института. Interrupt Injection тоже обходит защиту от Spectre v2 и позволяет читать произвольную память ядра Linux, причём на системах с процессорами Intel и AMD. Точные даты публикации обеих работ не указаны. Вместе эти техники показывают конкретную брешь в прежней модели защиты: удаление или замена исполняемого кода ещё не означает, что процессор забыл связанные с ним цели переходов, а полностью обновлённая система всё равно может выдать хеш пароля root за считаные минуты.[/final]


Новое на сайте

Ссылка