Дефекты проектирования Intel Core 2 Duo - AI39: Запрос кэш-линейки L1-кэша из одного ядра разрушает модифицированную кэш-линейку другого ядра

ОГЛАВЛЕНИЕ

AI39: Запрос кэш-линейки L1-кэша из одного ядра разрушает модифицированную кэш-линейку другого ядра, приводя к непредсказуемому поведению системы

  • Проблема: когда запрос данных из Ядра 1 приводит к «промаху» L1-кэша, запрос перенаправляется к L2-кэшу. Если же данная кэш-линейка уже находится в L1-кэше Ядра 2 и была им модифицирована, при определенных обстоятельствах Ядру 1 возвращается неверный результат.
  • Последствия: непредсказуемое поведение системы.
  • Решение: BIOS может справиться с этой проблемой.

Как известно, многоядерные процессоры имеют разделяемый (один на всех) L2-кэш и «индивидуальные» L1-кэши, фактически являющиеся частью ядра. В грубом приближении мы имеем обыкновенную многопроцессорную систему с разделяемой внешней памятью и внутрипроцессорной кэш-памятью. Для поддержания памяти в согласованном состоянии используются специальные когерентные протоколы, разработанные десятки лет тому назад. Казалось бы, в чем проблема?!

А в том, что создатели Core 2 Duo или забыли о когерентности (ну это уж вряд ли), либо, что более вероятно, реализовали ее неправильно. Насколько часто разные ядра работают с одними и теми же порциями данных? Очень часто! Ведь при переключении контекстов потоки, стартовавшие на одном ядре, рано или поздно оказываются на другом! Последние версии операционных систем линейки NT, Linux и BSD наконец-то научились отличать ядра от физических процессоров (в многопроцессорных системах) и потому стараются по возможности избегать переброски потоков с одного ядро на другое, поскольку при этом придется заново заполнять L1-кэш. Есть даже специальные API-функции для закрепления потоков за определенным процессором (ядром), но на практике они не используются, и программисты предпочитают доверять системному планировщику, алгоритм которого оптимизируется разработчиками операционной системы с учетом «характера» процессоров, имеющихся на рынке. Но в распоряжении планировщика – сотни потоков и обычно только два (редко четыре) ядра. Так что избежать «передислокаций» потоков невозможно, точнее, возможно, но уж слишком неэффективно.

Как можно использовать данный дефект для атаки? Самое простое – ничего не делать с системой. Она и сама упадет. Разрушение дисковых данных достаточно маловероятно, хотя и не исключено на 100%, а вот критические сбои приложений и голубые экраны смерти – вполне ожидаемое явление. Действительно, если программа что-то записала в память (на самом деле в кэш, но это уже не важно), а при последующем чтении не обнаружила никаких изменений, тут может произойти все что угодно.

Автору удалось реализовать разрушение кучи (динамической памяти) путем циклического выделения/освобождения крошечных блоков в Java-скрипте, следствием чего явился крах браузера. Чисто теоретически возможно разрушить кучу так, чтобы передать управление на shell-код, но для этого необходимо учитывать множество специфичных деталей, неизвестных удаленному атакующему, хотя в принципе достаточно предсказуемых.

Шторм запросов к любому драйверу (например, шторм IP-пакетов) также потенциально способен вызывать крах системы, но, учитывая, что шторма зачастую вызывают BSOD даже на «правильных» процессорах (из-за ошибок синхронизации, допущенных разработчиками драйверов), очень трудно определить, с каким дефектом мы имеем дело: с программным или аппаратным. Тем не менее хакерский потенциал у атак данного типа весьма весомый, что главным образом обуславливается простотой их реализации.

Самое непонятное в этой истории – какое отношение имеет BIOS с «разборкам» внутри процессора?! Единственное разумное предположение – BIOS просто заливает обновленный микрокод, предоставленный Intel. По-другому справиться с проблемой навряд ли получится.