[recovery mode] Spectre и Meltdown

Все как всегда, слышим звон, но не знаем где он.

В сети произошел очередной слив информации об двух уязвимостях в аппаратуре современных процессоров. Собственно уязвимость была открыта для публичного обсуждения одна, но методов ее эксплуатации было раскрыто два, под именами Spectre и Meltdown.
Для специалистов эта проблема оборудования известна давно, она «втихую» эксплуатировалась и все были довольны…

По какой то неизвестной причине о ней было решено раздуть шумиху, причем дилетантским способом, те кто выпускал официальные пресс-релизы (https://spectreattack.com/spectre.pdf и https://meltdownattack.com/meltdown.pdf) явно плохо представляли как все это работает и где проблема.
А поставщики исходной информации не удосужились подробно объяснить проблему, видимо передали работающий эксплоит и краткое описание для дилетантов…

Доморощенные комментаторы и знатоки ассемблера начали с умным видом обьяснять как все это работает.
Вот например статья, с кучей комментариев https://habrahabr.ru/post/346078/.
Особенно умиляет это:
image
«Наивный чукотский парень» не понимает для чего сдвиг на 1000h, да и вообще как все это работает, просто переводит своими словами такой же безграмотный текст оригинального пресс-релиза.

Придется объяснять.

Реальное место расположения уязвимости в аппаратуре

Уязвимость расположена здесь, она выделена красным кружком:
image
Проблема в блоке TLB, который используется в пейджинговой адресации оперативной памяти. Он является ассоциативным буфером хранящим пары значений виртуальный-физический адрес используемой приложением в оперативной памяти.
Это не Кеш данных….

Вот как его описывает в документации фирма Интел:
image
Блок TLB нужен для того чтобы сократить время обращения к ОП за счет исключения процедуры трансляции адресов памяти. Такая трансляция производится единственный раз для всей страницы (размером как раз 4К в случае современных ОС). Все остальные обращения программы к памяти в этой странице уже происходят форсированно, с использованием сохраненного значения в этом буфере. Эти блоки есть во всех современных процессорах, собственно из-за этого все они и подвержены уязвимостям называемым теперь Spectre и Meltdown.
И кстати, спекулятивное выполнение команд не единственная возможность эксплуатации этих уязвимостей, можно задействовать механизм форвардной загрузки данных из ОП.

Блок TLB не имеет программного (микропрограммного) управления, как обычный кеш. Из него невозможно удалить запись, либо принудительно внести/модифицировать какую-либо запись.

В этом и заключается аппаратная уязвимость, все произведенные трансляции адресов сохраняются в этом ассоциативном буфере.

Соответственно произведенная спекулятивно операция тоже оставит в блоке TLB cлед в виде записи, нужно только эту запись обнаружить и идентифицировать. А это уже «дело техники», технология давно известна и применяется, она называется «Исследование состояния аппаратуры методом временного прозвона». Не ищите этого названия в Интернете, метод был известен в очень узких кругах совершенно не публичных специалистов.

А вот теперь с ним будут знакомы все…

Единственная возможность программного воздействия на блок TLB, — это полный сброс всех его значений (ну тут я немного лукавлю исключительно для простоты понимания). Все патчи уязвимостей Spectre и Meltdown предложенные производителями ПО это и делают, перезагружая в обработчике исключения GP регистр CR3.
После сброса TLB процессору приходится заново выполнять трансляции всех используемых страниц виртуальной памяти, это и снижает производительность системы.

Как все это эксплуатируется в реальности

Первым делом нужно в программе создать буфер размером 2 мегабайта, причем в этот буфер нельзя писать/читать до проведения атаки и он должен располагаться на границе 4К блока. Этот размер принципиален, в буфере должны разместиться ровно 256 страниц по 4К (специфика пейджинговой адресации).

Затем выполняются команды типа:

image

В программе после команды Mov al, [адрес ядра ОС]; произойдет прерывание и значение регистра al не изменится (останется нулевым).
А вот в буфере TLB из-за форвардного запроса выполнения операции произойдет запоминание вычисленного соответствия виртуального адреса и физического адреса [ebx+eax].
Сбросить эту конкретную запись, как это делается в обычном Кеше, в блоке TLB невозможно и она останется…

Соответственно если мы узнаем адрес страницы размером 4К в буфере размером 2М, запомненный в блоке TLB, то мы узнаем и значение прочитанное из ядра ОС в регистр al.
Это уже дело техники, «прозвоним» блок TLB. Для этого нужно по одному разу прочитать все его страницы по 4К, их ровно 256, выполним 256 операций чтения (одну на каждый 4К блок). При этом будем измерять время выполнения операции чтения. Та страница, которая будет читаться быстрее остальных, и будет иметь номер в буфере размером 2М соответствующий прочитанному значению байта из ядра ОС.

Это произойдет потому, что в буфере TLB для этой страницы уже вычислено соответствие между виртуальным и физическим адресом, а для всех остальных страниц этой операции выполнено еще не было.
В «прозвоне» конечно не все так просто, там много нюансов, но это вполне возможно.
Делали, знаем…

Вот собственно и все.

© Habrahabr.ru