Как работает Meltdown


Новости полны атак Meltdown и Spectre, которые, похоже, работают на широком спектре современных процессоров, особенно на процессорах Intel, выпущенных с 1995 года. Интересная часть истории заключается в том, как работают эксплойты и как они могли быть встроены в процессоры так долго, чтобы никто не заметил.

См. Также: Как работает Spectre

Из двух эксплойтов Metldown легче понять, внедрить и, по-видимому, защитить от него. Это связано с тем, что современный процессор пытается запускать программы быстрее, используя спекулятивное выполнение. Если вы знаете, как работают процессоры на простейшем уровне, вы можете быть удивлены, обнаружив, насколько сложным стал современный процессор. Например, большинство современных ЦП будут выполнять код параллельно, включая код, который может никогда не понадобиться. Обычный пример – предсказание ветвления. Если поток управления разделяется оператором if, вы можете ускорить работу, выполнив наиболее вероятную ветвь перед тестом. Вы можете обнаружить, что оценили неправильную ветвь, то есть тогда, а не else, но тогда вы просто отбрасываете свои вычисления и начинаете с другой ветки.

Все это кажется очень невинным, и сама идея спекулятивного исполнения не кажется угрозой безопасности. Что возможно могло пойти не так?

Конечно, изобретательный ум «хакера» способен превратить даже самую невинную особенность в эксплойт, и так происходит со спекулятивным исполнением. Предположим, вы пишете код, который загружает данные из защищенной области операционной системы – ядра – и использует эти данные для вычисления адреса элемента в массиве для доступа к чему-то вроде:

data = getByte (kernalAddress) переменная = probeArray (данные)

Инструкция getByte возвращает значение в диапазоне от 0 до 255, и это используется для доступа к элементу probeArray, длина которого составляет 255 элементов. Если бы это сработало, вы бы успешно прочитали байт данных из ядра – то, что вы не должны делать, потому что это личные данные, включающие пароли, ключи и так далее. На самом деле это не работает, потому что память ядра защищена, и инструкция getByte завершится ошибкой с исключением времени выполнения, а остальная часть вашей программы завершится. Вы никогда не получите доступ к элементу массива на основе данных.

Теперь добавим спекулятивное исполнение. Процессор, скорее всего, спекулятивно выполнил доступ к probeArray до того, как возникнет исключение – исключения сложны и медленны. Это все еще не проблема безопасности, потому что спекулятивные результаты выбрасываются и не доступны в пользовательском пространстве.

Никакого вреда не нанесено, поскольку спекулятивное исполнение в конечном итоге не внесло никаких изменений в систему.

Не совсем верно, потому что к элементу probeArray был осуществлен доступ, и он теперь находится в системном кеше. Перед запуском программы мы убедились, что ни один из элементов probeArray не находится в кеше. Итак, теперь все, что нам нужно сделать, это прочитать каждый элемент probeArray и измерить, сколько времени занимает доступ. Доступ, который происходит быстрее, чем остальные, – это элемент, который был кэширован спекулятивным выполнением. Как только мы узнаем, какой элемент был кэширован, мы узнаем значение данных.

Спекулятивное выполнение изменило архитектурное состояние ЦП, и это обеспечивает скрытый канал, по которому мы можем переправлять секретные данные.

Это означает, что теперь мы можем читать любую ячейку памяти ядра и обнаруживать, что там хранится, просто пытаясь выполнить незаконный доступ и используя спекулятивное выполнение и кеширование, чтобы найти, какие данные были бы получены, если бы они не были незаконными.

Вот как работает Meltdown с некоторыми дополнениями и сложностями из реального мира. Обнаружившие уязвимость исследователи реализовали ее и смогли прочитать любую ячейку памяти ядра:

«Благодаря обработке исключений мы достигли средней скорости чтения 123 КБ / с при утечке 12 МБ памяти ядра. Из 12 МБ данных ядра только 0,03% были прочитаны неправильно. Таким образом, с частотой ошибок 0,03% канал пропускная способность 122 КБ / с ».

Meltdown на самом деле не работал на процессорах AMD и ARM в том смысле, что он не извлекал какие-либо действительные данные, однако было показано, что общий принцип работает – обе архитектуры действительно выполняли инструкции, помимо незаконных. Предполагается, что причина, по которой это не сработало, может заключаться в точном времени возникновения исключения, и все, что требуется, – это небольшая настройка кода.

Исправление для Meltdown состоит в том, чтобы отключить любое отображение памяти между ядром и пользовательской памятью, за исключением областей, которые необходимо совместно использовать, например таблиц прерываний. Это делается с помощью патча KAISER, доступного для Linux. Более продвинутая и лучшая защита требует использования косвенного обращения для сокрытия адресов ядра – кода трамплина. Это замедляет программы, которые часто используют систему.

«Meltdown полностью меняет ситуацию. Meltdown смещает степень детализации со сравнительно низкой пространственной и временной детализации, например, 64 байта каждые несколько сотен циклов для атак на кэш, на произвольную гранулярность, позволяющую злоумышленнику читать каждый бит. Это ничто. любой (криптографический) алгоритм может защитить себя. KAISER – это краткосрочное программное решение, но проблема, которую мы обнаружили, гораздо более серьезна ».

Вы можете обвинить Intel и других производителей оборудования, если хотите, но проектирование оборудования для обеспечения производительности – сложная задача. Спроектировать его для обеспечения производительности и безопасности практически невозможно:

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


Добавить комментарий