Страницы

Поиск по вопросам

воскресенье, 24 ноября 2019 г.

В чём смысл уязвимости Meltdown?


Недавно стало известно об уязвимости Meltdown, которая затрагивает большинство процессоро
Intel. В чём она заключается? Как функционирует атака? Как можно сдетектировать атаку и/или защититься от неё?
    


Ответы

Ответ 1



Смотрите, в чём дело. У многих современных процессоров есть так называемое спекулятивное выполнение. Что это такое? Дело в том, что компьютерная память медленная, а выполнение инструкций быстрое. Поэтом если условный переход зависит от значения, лежащего в памяти, то процессор во врем ожидания, пока из памяти «подгонят» нужное значение, может начать выполнять инструкци той ветки, которую он считает более вероятной. Эти инструкции выполняются «секретно», их результаты не видны до тех пор, пока не произойдёт реальная подгрузка ожидаемого значения из памяти и процессор реально не убедится, что выполнение таки-пойдёт по ожидаемой ветке. Если выполнение реально пойдёт по нужной ветке, побочные эффекты «секретно» выполненны операций публикуются процессором и становятся видимыми другим инструкциям. Если же выполнение не пойдёт по нужной ветке, спекулятивно выполненные команды аннулируются, и их результат никому не виден. Однако, эти отменённые команды могут всё же производить побочные эффекты, наблюдаемы из нашего кода. Если отменённая команда читала память, которая не была загружена в кэш процессора, то эта память грузилась в кэш процессора, и последующее обращение к ней было быстрее. Таким образом, можно судить о том, что же делала отменённая команда. Каким образом можно это использовать? Мы можем в спекулятивно выполняемом коде зависимости от считанных данных подгрузить в кэш различные куски памяти, и измерив время доступа к ним, решить, какие же данные были прочитаны. Чем это отличается от обыкновенного чтения данных? Вот тут-то и проявляется ошибк в Intel'овских процессорах. Дело в том, что мы можем спекулятивно читать память ядра, которая нам недоступна. Ошибка заключается в том, что при спекулятивном чтении не проверяются права на доступ к памяти. Итак, наш код выглядит следующим образом: Мы выделяем участок памяти X, по длине больший, чем несколько линий кэша. Мы сбрасываем кэш так, чтобы память X не была в кэше. (Например, так.) Мы определяем адрес в ядре, который мы хотим прочитать, и записываем его в указатель p. Мы пишем код вида if (data == 0) { byte kernelByte = *p; byte dummy = X[(kernelByte & 1) * CACHE_LINE_SIZE]; } В data мы кладём ненулевое значение, и вытесняем data из кэша. Мы выполняем указанный код, после чего измеряем время доступа к X[0] и X[CACHE_LINE_SIZE]. Что происходит? Весь код внутри if не выполняется в реальности, но выполняется лиш спекулятивно. Про спекулятивном выполнении чтение по указателю на память ядра завершаетс успешно. В зависимости от значения младшего бита спекулятивно прочитанного значения мы производим доступ к одной из двух кэш-линий. Таким образом, одна из кэш-линий окажется загруженной в результате спекулятивного выполнения. Если время доступа к X[0] близко к типичному времени доступа к закэшированной памяти то в спекулятивном коде было обращение к X[0], и значит, kernelByte & 1 == 0. Если врем доступа к X[CACHE_LINE_SIZE] близко к типичному времени доступа к закэшированной памяти, то в спекулятивном коде было обращение к X[CACHE_LINE_SIZE], и значит, kernelByte & 1 == 1. Таким образом, мы смогли прочитать один бит защищённой памяти. Далее, один за одни можно считывать информацию. На текущий момент скорости считывания составляют около 1-2 килобайт в секунду. Процессоры AMD не подвержены атаке Meltdown. Если верить информации от инженера AMD, AMD processors are not subject to the types of attacks that the kernel page table isolation feature protects against. The AMD microarchitecture does not allow memory references, including speculative references, that access higher privileged data when running in a lesser privileged mode when that access would result in a page fault. Параллельно с описанной атакой Meltdown есть очень похожая, в некотором смысле более общая атака, известная как Spectre. В ней «недоступная» память читается так же, но не через границы уровней доступа То есть, читается не ядро, а память собственного процесса (или, возможно, даже другог процесса, бегущего с теми же правами!). Этой уязвимости подвержены уже и процессоры AMD, потому что блокировка спекулятивного выполнения на уровне процессора «не видит» границ между процессами, т. к. процесс — понятие уровня операционной системы. Зачем может понадобиться читать память своего же процесса? Например, для выхода и «песочницы». Код на JS в браузере обычно бежит в том же процессе, с теми же правами а контроль над тем, чтобы JS не читал память за границами положенного, возложена на код, который проверяет выход индексов за границы диапазона. Как мы уже видели, выход индекса за границы диапазона возможен даже при контроле значения индекса при спекулятивном исполнении кода. Обе атаки полностью пассивные, «молчаливые», поэтому на текущий момент не существуе защиты или метода обнаружения атак, который мы как пользователи смогли бы использовать. Единственный способ защититься от Meltdown — ждать патча операционной системы. Патч для Meltdown заключается в том, что из виртуального пространства процесса операционная система убирает память ядра. Это замедляет системные вызовы, но исправляет данную проблему. Майкрософт выпустила патч против Meltdown для Windows 10 3.01.2018 как KB4056892 Убедитесь, что он у вас поставлен (если у вас, конечно, Windows 10). Это можно сделать, например, при помощи PowerShell: PS > Install-Module SpeculationControl PS > Get-SpeculationControlSettings Apple включила защиту от Meltdown в iOS 11.2, macOS 10.13.2 и tvOS 11.2. Проверьте вашу версию системы, если у вас Мак или i-устройство! Обновления для Ubuntu практически готовы, и ожидаются 9.01.2018 (или раньше, если получится). Не пропустите их. Одна из неприятностей данных уязвимостей состоит в том, что атаку при определённых условиях можно проводить даже из Javascript. Чтобы защититься от атаки Meltdown из javascript'а других сайтов, можно его временн отключить до выхода патча, но вы же не станете этого делать? Патча на Spectre для операционной системы нет, и он невозможен: уязвимость нужно исправлять в браузере. Производители браузеров тоже прилагают усилия, чтобы было сложнее воспользоваться уязвимостью из Javascript. Firefox включает изменения, направленные на борьбу с уязвимостью, начиная с уже вышедшей версии 57, и усиливает защиту в версии 57.0.4 (бета). Хром выпустит изменения в JS-движке V8 23 января (версия 64), но уже начиная с сегодняшнег дня будет предупреждать об использовании подозрительного API. На сегодняшний день Гугл рекомендует поставить последнюю версию Хрома и включить Site Isolation. Edge и Internet Explorer получили изменения, направленные на борьбу с использованием уязвимости, начиная с уже вышедшего обновления KB4056890. Улучшения браузеров мешают JS-коду получить точное время для измерения времени выполнени участков кода. Это, к сожалению, не закрывает полностью атаку Spectre, потому что изобретательный взломщик может найти способ измерять время другими методами. Поэтому Spectre, на эмблеме которого изображено привидение, будет ещё долго появляться и пугать нас. Небольшое обновление: в выпущенной сегодня (26.01.2017) версии Visual Studio компилято C++ включает новый ключ /Qspectre, который защищает скомпилированные программы от утечки данных через Spectre. Официальное объявление здесь.) Литература: Project Zero, Reading privileged memory with a side-channel Wikipedia: Meltdown Geektimes: Новогодние подарки, часть первая: Meltdown Отдельное спасибо участникам @PashaPash и @Arhad, обсуждение с ними очень помогло прояснить общую картину и яснее понять проблематику.

Ответ 2



В чём она заключается Внимание: текст ниже является донельзя утрированным и однобоким описанием работ процессора, в котором опущены многие важные детали. Однако это вынужденная мера для упрощения понимания сути атаки. 1. Многопоточность там, где её не ждут Все относительно современные процессоры выполняют данные не последовательно, команд за командой, а параллельно, кучей команд за раз. Это называется суперскалярная архитектура. Однако любой параллелизм ломается ветвлениями (условиями, циклами и заходами в функции) Процессор не телепат, а потому не знает, куда именно пойдёт выполнение на очередно развилке. Поэтому он отслеживает, куда выполнение идёт чаще всего, и упреждающе помещает в параллельное исполнение команды именно этой ветки. Это называется спекулятивное исполнение. Но процессор может и ошибаться, а потому все операции с регистрами и памятью в это ветке перенаправляются во временное хранилище, так называемые временные регистры, содержимое которых записывается по назначению только при удачном переходе по ожидаемой ветке. В противном случае их содержимое отбрасывается. Иными словами, весь выполняемый на упреждение код как бы сидит в «песочнице». И во тут инженеры Intel допустили оплошность с целью оптимизации. Мол, если запись при упреждающе выполнении невозможна до известного процессору момента, то и все проверки безопасности можно отсрочить до того же момента — всё равно в случае чего данные будут бесследно отброшены. Если бы инженеры знали, как они жестоко просчитались насчёт понятия «бесследно» Да, временные регистры абсолютно изолированы. Но у инструкций, выполняемых на опережение, имеется доступ не только к регистрам, но и к такой долгоживущей штуке, как кэш. 2. Сага о кэше Кэш — это место, куда процессор временно складывает копии фрагментов оперативно памяти. Зачем он это делает? Всё просто. Оперативная память — штука крайне медленная требующая сотни тактов на чтение одного байта. Потеря сотни тактов на каждый чих — непозволительна роскошь, да и из всей оперативной памяти программе, как правило, требуется совсем немного. Поэтому всю память условно разбивают на череду блоков по 64 байта каждый, а процессор снабжают небольшим (32КБ) количеством сверхбыстрой памяти, в которую он копирует те из блоков, что пытается читать программа. Блочность используется в предположении, что программа будет не скакать по оперативной памяти, а располагать данные компактно. Вроде бы всё понятно и очевидно. Ах, да, кэш можно выборочно (поблочно) очищать дл возможности получения наисвежайших данных из оперативной памяти. И ещё, если нужного блока в кэше ещё (либо уже) нет, команда-инициатор обращения приостанавливается и ждёт свои сотни тактов, пока блок не будет готов. 3. В гостях у проктолога, или используем стандартные средства нестандартным способом Вы ещё не заметили ничего необычного? Значит вы не хакер (в исконно-благородном смысл этого слова). Ведь если принять каждый блок в кэше за один бит, а его пустоту/полнот за ноль и единицу соответственно, то мы получим прекрасное хранилище данных. Кратковременное, конечно, — до близжайшего массового сброса переключением задач, — да и объём подкачал. Но всё равно оно прекрасно. Вы спросите: чем? Да тем, что к этому «хранилищу» имеют доступ инструкции из опережающег выполнения, упомянутого в начале (далее ОП)! То есть получается следующая воистину гениальная картина: ОП, с одной стороны, имеют неподконтрольный и неограниченный доступ ко всей оперативно памяти (включая память ядра ОС, лежащую в верхнем диапазоне адресов). Ведь, как был сказано выше, все проверки будут выполнены позднее, когда настанет черёд проверки взятия условного перехода и записи изменений в регистры и память. А пока за нами никто не следит, мы с ОЗУ наедине — спасибо вам, инженера Intel! С другой стороны, ОП имеют доступ к кэшу. Записать туда, конечно, ничего нельзя (эт кэш чтения, а не записи), но можно сделать из него вышеописанное «хранилище» (заране сбросив его) и производить чтение из определённых блоков памяти, отправляя их в кэш (мы условились, что это запись единичных бит в хранилище). С кэшем мы тоже наедине — ведь выполнение опережающее, а потому нас пока как бы и нет. То, что нас потом, возможно, отбросят, неважно — мы уже успеем поиграть с кэшем. А на стыке этих двух вещей рождается поистине грандиозная атака по побочным каналам позволяющая втихаря читать любую память, включая привелегированную, и отправлять её содержимое наружу. Осталось решить только две проблемы: как впоследствии читать из такого «хранилища», как быть с посланным вдогонку прерыванием о нарушении страничной защиты; ведь неизбежн настанет момент сохранения временных результатов, при котором и вскроется наше переступление границ памяти. 4. Практическое использование Первая проблема решается достаточно легко. Для этого достаточно пробежаться по все той памяти, которой соответствуют использованные для «хранилища» записи кэша. Те блоки которые не были тронуты (то есть как бы обозначают ноль) будут считываться значительн медленнее (помним про сотни тактов?), чем те, которые были принудительно предзагружены (то есть обозначают единицу). Если время доступа вообще неприличное, значит у нашего процесса истекло время исполнения и его вытеснили другим — повторяем запрос. Ну а точное время выполнения команды можно узнать у самого процессора с точностью до такта, благо есть соответствующая ассемблерная команда. А вот у второй проблемы есть целых два решения, которые и известны как те самые Meltdown и Spectre: Можно вообще плюнуть на исключение, благо степень параллелизма у современных процессоро большой, и мы спокойно (если повезёт) успеем прошерстить блоки памяти и восстановить переданное число. Это Meltdown. Можно обмануть процессор, пустив выполнение по неожиданной для него условной ветви Тогда исключения не возникнет в принципе, так как всё исполнение будет ошибочно-излишним. Ну а про побочный эффект где-то в районе кэша никто никогда и не узнает. Это Spectre. Вот и вся суть обеих нашумевших уязвимостей. Кстати, это не гипотетические изыскания а практичные вещи, с использованием которых исследователи спокойно копировали ядерную память стабильным потоком в пару килобайт в секунду. Как защититься Если вы пользователь — то никак. Уязвимость слишком низкоуровневая. Если вы разработчик программ или операционных систем — сбрасывайте участки кэш-памяти с чувствительными данными перед передачей управления стороннему коду. Если вы разработчик микрокода в компании Intel — перенесите все проверки правомерност доступа с этапа применения команд на этап опережающего исполнения, как уже давно сделано у AMD. И не тяните с выпуском обновления микрокода.

Ответ 3



Найдено на самом деле две разных уязвимости с похожим механизмом но с совершенн разными последствиями: Meltdown - Rogue Data Cache Load Подвержены Intel и некоторые из ARM. Позволяет читать память ядра из юзермода. Прикрывается только патчем на OS, которы перестает мапить память ядра, что бьет по производительности (и вызывает промахи кэша при системных вызовах). Позволяет процессу без ограничений читать память других процессов. Позволяет коду в одной виртуальной машине читать память хоста и других виртуальных машин. Последнее - и есть основная проблема. Затронуты все хостеры, включая Amazon и Azure. Иcправления: Windows KB4056892 Linux - ядра 4.14.11, 4.9.75 и будущее 4.15. MacOS - 10.13.2/10.13.3 Никакое "отключение JS" не помогает. Апдейта микрокода не будет. Единственный вариан - патч на операционку, который достаточно сильно бьет по производительности на IO-intensive workload (сеть и базы данных). В играх - никакой разницы. Долгосрочные последствия: Интел выпустит новые исправленные процессоры, на 30% быстрее которые раскупят намного быстрее, чем 8-е поколение. Хостеры, предоставляющие VM на исправленных процессорах, поднимут цены. Spectre - Bounds Check Bypass + Branch Target Injection Подвержены Intel, AMD и ARM. Позволяет обойти проверки вида if (x < array1_size) y = array1[x]; при доступе массиву в рамках одного процесса, выполняя код в том же процессе. Основная проблема: позволяет коду на JavaScript обойти защиту и читать всю память процесса-браузера. Исправления ожидаются со стороны уязвимых приложений: Firefox v57. Хром v64. Edge и Internet Explorer - KB4056890. Исправления браузеров никак не отключают сам Branch Prediсtion. Они снижают точност performance.now и временно отключают SharedArrayBuffer (был использован как таймер авторами атаки для Chrome). И, наверное, переписывают подверженные уязвимости проверки. Долгосрочные последствия: Пострадают, прежде всего, разработчики браузеров. Всем кто запускает в своем процессе сторонний код, придется очень аккуратно бороться с возможностью прочитать память всего процесса.

Комментариев нет:

Отправить комментарий