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

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

Ответ
Смотрите, в чём дело.
У многих современных процессоров есть так называемое спекулятивное выполнение. Что это такое?
Дело в том, что компьютерная память медленная, а выполнение инструкций быстрое. Поэтому если условный переход зависит от значения, лежащего в памяти, то процессор во время ожидания, пока из памяти «подгонят» нужное значение, может начать выполнять инструкции той ветки, которую он считает более вероятной. Эти инструкции выполняются «секретно», их результаты не видны до тех пор, пока не произойдёт реальная подгрузка ожидаемого значения из памяти и процессор реально не убедится, что выполнение таки-пойдёт по ожидаемой ветке.
Если выполнение реально пойдёт по нужной ветке, побочные эффекты «секретно» выполненных операций публикуются процессором и становятся видимыми другим инструкциям. Если же выполнение не пойдёт по нужной ветке, спекулятивно выполненные команды аннулируются, и их результат никому не виден.
Однако, эти отменённые команды могут всё же производить побочные эффекты, наблюдаемые из нашего кода. Если отменённая команда читала память, которая не была загружена в кэш процессора, то эта память грузилась в кэш процессора, и последующее обращение к ней было быстрее. Таким образом, можно судить о том, что же делала отменённая команда.
Каким образом можно это использовать? Мы можем в спекулятивно выполняемом коде в зависимости от считанных данных подгрузить в кэш различные куски памяти, и измерив время доступа к ним, решить, какие же данные были прочитаны.
Чем это отличается от обыкновенного чтения данных? Вот тут-то и проявляется ошибка в 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, обсуждение с ними очень помогло прояснить общую картину и яснее понять проблематику.