"… method takes advantage of speculative execution after conditional branch instructions"
Intel рекомендует вставлять LFENCE после условного перехода. Что-то не верится в 1.5%, если после каждого перехода будет LFENCE.
Что касается Branch target injection и предлагаемого патч по имени retpoline для этого в LLVM/gcc, то он убивает execution stack protection — запрет на выполнение кода из стэка. Попросту — открывает новые горизонты для хакеров!
Однако я уже лет 8 работаю в компаниях занимающихся high performance/high bandwidth и разработкой процессоров. Лет 7 назад я ломал голову, почему пара тривиальных процессов, обменивающихся сигналами или просто перекидывающих друг другу 1 байт на 7i core с 4 процессорами/8 thread-ами работает в 5 (ПЯТЬ, Карл!) раз медленнее, чем когда на машине запустить 8 таких пар. Я нашел — при power-saving ядру надо восстанавливать таблицы страниц, при полной загрузке этого power-saving просто нет.
> А теперь представьте себе: из L0 одного ядра нужно число переправить в L0 другого ядра. Это сотни тактов, и этот эффект больше, чем то, что мы хотим измерять
Это не совсем верное рассуждение:
1. Это по любому не сотни циклов.
2. Применяют хитрости для сокращения времени.
3. Загрузку всегда делают в pipeline к операции. Тут конечно большая наука намешана, чтобы соблюсти когерентность данных.
Но когеретность времени тут не соблюдается. Просто доступ из локального кэша много короче следующего уровня, вот схема опроса счетчика и работает.
> Процессор не исполняет ничего «на всякий случай». Он не пытается «хватать» инструкции «где-то рядом» с потоком исполнения и рандомно их исполнять — это бессмысленно. На некоторых CRAY системах пытались одновременно спекулятивно исполнять команды на обоих ветвях после перехода… идея себя не оправдала.
На CRAY не оправдала, на MIPS например — оправдала. И вы немного не в курсе, почему часто отрабатывают тщательнЕе код, который внутри loop — просто есть такая штука как instruction parsing (особая головная боль для Интела) и branch-table — код внутри короткой петли уже разобран в процессоре на микроинструкции и все возможные операции уже сделаны. Посему можно сделать speculative операцию довольно легко. Но это для low-end процессоров, для high-end надо смотреть в обе стороны условного перехода.
Кстати, далеко вперед обычно не смотрят, просто парсят и запускают операции загрузки из памяти (ну очень уж они долгие, особенно если учесть возможность подкачки TLB из памяти), и (внимание!) — простейшие операции над адресами в случае индексирования и последующей второй загрузки над результирующим адресом. Вот мне кажется, что AMD не делает либо индексирование либо вторую загрузку, которая зависит от первой. Посему они такие гордые сегодня.
> Если загрузка после проверки «спекулятивно сработала» (а потом не понадобилась) — то это значит, что предсказатель переходов сработал неверно.
Это важно только в случае узкого канала в память. Если у вас хороший кэш, то большинство неверных предсказаний окончится в кэше и чуть потратит рессурсы LFU-или-как-его-там, которых все равно делают в расчете на speculative.
> А вы предлагаете на это событие, случающееся с ничтожной вероятностью, полагаться.
Это как в анекдоте — 50-на-50. Маленьких циклов, которые полностью оседают в процессоре — мало, большая часть циклов просто не обнаруживается процессором. Так что с этой точки зрения выгодно отрабатывать чуть-чуть вперед по обе стороны условного перехода.
Это кранты, это ЕЩЕ ОДИН баг. Поставить внутри guest VM последовательность спекулятивной загрузки карты памяти root-а (!) + чтения слова из этой памяти ==> в TLB будет лежать доступ в память root-а из guest-а.
Если это еще работает (все-таки 7 лет прошло), то весь облачный сервис накрылся медным тазом, сбацать дырокол для тех процессоров — нефиг делать. Ох, заставят всех обновить процессоры, заставят.
Так такой «нехороший код» гораздо чаще в ядре или программе случается! И защититься от него много сложнее через LLVM/gcc.
Но почитав о чем народ талдычит, складывается впечатление, что якобы Интел не делает speculative пока по коду не проползет несколько раз циклом(!) Очень странная мысль, я сидел на одном семинаре где они хвастались, что они просматривают вперед аж на 3 условных перехода длинным pipeline — нахрена тогда им это делать то?
Или это конкретный процессор такой, а народ и не знает?
Не требует. В цепочку спекулятивных выполнений можно поставить операцию типа address = вытащенный байт * адрес массива. Далее — опредилить, какая строчка массива была вытащена в кэш, например чтением всех строк и измерением времени. Все, значение выдернутого спекулятивно байта известно.
Фиксом в LLVM/gcc можно попробовать решить проблему Spectre, Meltdown же вообще не трогает ядро и качество кода ядра не влияет на него. Кроме как временное отключение kernel maps при выходе в моду пользователя, что и делает вышедший патч.
Вообще-то я не понимаю, почему они сосредоточились только на переходе по регистру. Простой условный переход, условие которого вычисляется в зависимости от неизвестного в данный момент значения может скорее всего вызвать выдергивание кэш строки по известному адресу в команде загрузки сразу за этим переходом.
Я не силен в x86 ассемблере (забыл его), но что-то типа
— вычисление условия А, например по слову из памяти или как последнее в цепочке вычислений
— условный переход по условию А, который всегда выполняется в нормальной ситуации
— загрузка слова по регистру, который известен задолго до и который содержит «нехороший» адрес.
В нормальном выполнении загрузка никогда не срабатывает, так как условный переход идет нафиг всегда. При спекулятивном выполнении есть большой соблазн запустить эту загрузку на всякий случай заранее, хотя в момент запуска еще не известно значение условия А. Приплыли.
> Да неужели?
Вперед и с песней — выполнение этой инструкции из user программы запрещено.
"… method takes advantage of speculative execution after conditional branch instructions"
Intel рекомендует вставлять LFENCE после условного перехода. Что-то не верится в 1.5%, если после каждого перехода будет LFENCE.
Что касается Branch target injection и предлагаемого патч по имени retpoline для этого в LLVM/gcc, то он убивает execution stack protection — запрет на выполнение кода из стэка. Попросту — открывает новые горизонты для хакеров!
Однако я уже лет 8 работаю в компаниях занимающихся high performance/high bandwidth и разработкой процессоров. Лет 7 назад я ломал голову, почему пара тривиальных процессов, обменивающихся сигналами или просто перекидывающих друг другу 1 байт на 7i core с 4 процессорами/8 thread-ами работает в 5 (ПЯТЬ, Карл!) раз медленнее, чем когда на машине запустить 8 таких пар. Я нашел — при power-saving ядру надо восстанавливать таблицы страниц, при полной загрузке этого power-saving просто нет.
На AMD этого кстати не было.
Это не совсем верное рассуждение:
1. Это по любому не сотни циклов.
2. Применяют хитрости для сокращения времени.
3. Загрузку всегда делают в pipeline к операции. Тут конечно большая наука намешана, чтобы соблюсти когерентность данных.
Но когеретность времени тут не соблюдается. Просто доступ из локального кэша много короче следующего уровня, вот схема опроса счетчика и работает.
На CRAY не оправдала, на MIPS например — оправдала. И вы немного не в курсе, почему часто отрабатывают тщательнЕе код, который внутри loop — просто есть такая штука как instruction parsing (особая головная боль для Интела) и branch-table — код внутри короткой петли уже разобран в процессоре на микроинструкции и все возможные операции уже сделаны. Посему можно сделать speculative операцию довольно легко. Но это для low-end процессоров, для high-end надо смотреть в обе стороны условного перехода.
Кстати, далеко вперед обычно не смотрят, просто парсят и запускают операции загрузки из памяти (ну очень уж они долгие, особенно если учесть возможность подкачки TLB из памяти), и (внимание!) — простейшие операции над адресами в случае индексирования и последующей второй загрузки над результирующим адресом. Вот мне кажется, что AMD не делает либо индексирование либо вторую загрузку, которая зависит от первой. Посему они такие гордые сегодня.
> Если загрузка после проверки «спекулятивно сработала» (а потом не понадобилась) — то это значит, что предсказатель переходов сработал неверно.
Это важно только в случае узкого канала в память. Если у вас хороший кэш, то большинство неверных предсказаний окончится в кэше и чуть потратит рессурсы LFU-или-как-его-там, которых все равно делают в расчете на speculative.
> А вы предлагаете на это событие, случающееся с ничтожной вероятностью, полагаться.
Это как в анекдоте — 50-на-50. Маленьких циклов, которые полностью оседают в процессоре — мало, большая часть циклов просто не обнаруживается процессором. Так что с этой точки зрения выгодно отрабатывать чуть-чуть вперед по обе стороны условного перехода.
Если это еще работает (все-таки 7 лет прошло), то весь облачный сервис накрылся медным тазом, сбацать дырокол для тех процессоров — нефиг делать. Ох, заставят всех обновить процессоры, заставят.
Но почитав о чем народ талдычит, складывается впечатление, что якобы Интел не делает speculative пока по коду не проползет несколько раз циклом(!) Очень странная мысль, я сидел на одном семинаре где они хвастались, что они просматривают вперед аж на 3 условных перехода длинным pipeline — нахрена тогда им это делать то?
Или это конкретный процессор такой, а народ и не знает?
Это насчет того, сработает нехороший код или нет.
Meltdown легко сделать, даже в JS. И он не работает на AMD.
Spectre значительно труднее сделать, по крайней мере Гуглу пришлось воспользоваться eBPF, который по умолчанию выключен.
Я не силен в x86 ассемблере (забыл его), но что-то типа
— вычисление условия А, например по слову из памяти или как последнее в цепочке вычислений
— условный переход по условию А, который всегда выполняется в нормальной ситуации
— загрузка слова по регистру, который известен задолго до и который содержит «нехороший» адрес.
В нормальном выполнении загрузка никогда не срабатывает, так как условный переход идет нафиг всегда. При спекулятивном выполнении есть большой соблазн запустить эту загрузку на всякий случай заранее, хотя в момент запуска еще не известно значение условия А. Приплыли.
Достаточно одного, а он точно найдется.
Но проблема в том, что нужно еще и чистить кэш таблиц страниц, и они должны каждый раз подкачиваться обратно. Вот и греется.
Можно сбрасывать кэш (весь!) и тогда ни meltdown, ни spectre, но тут потеря будет В РАЗЫ.
Если же делать ежедневные операции с диском или локальной сетью, которые и так занимали заметное время, то просадка будет значительна.
«Variant Three Rogue Data Cache Load Zero AMD vulnerability due to AMD architecture differences.»
Да и Гуглы не смогли его там запустить.
А в табличке там полно AMD…