Интел предлагает вставлять LFENCE после условного перехода для фикса Варианта-1, и использовать команды PUSH + RET вместо перехода по регистру. Вроде LLVM/gcc уже даже патч есть.
Че-то у нас дискуссия ушла в не очень хорошую сторону — как лучше отхачить, через TLB miss или cache miss. Лекарство то тоже самое, убрать маппинг ядра, поэтому пусть в этот вопрос углубляются инженеры Интела.
Что касается PCID, то это очевидная оптимизация, но не везде и надо смотреть на общий случай если взвешивать др. варианты.
Я еще смотрел на возможность анализировать user код после exception и очищать строку кэша/TLB, но этот вариант, хотя и быстр по части потерь производительности, не пригоден, так как атака будет быстро реверснута — будет поиск очищеной строки кэша или TLB, увы.
Дополнение к вопросу — TLB vs cache: Судя по тому, что для предотвращения meltdown пошли по пути сброса TLB а не кэша, народ тоже считает, что сохранение кэша более важно. Что как бы намекает, что и железячные люди в том же консенсусе и приняли меры к удержанию строчек в кэше ==> обновление конкретной строки кэша случается реже, чем элемента TLB.
Ну вы же понимаете, официальные факты тут может предъявлять только AMD. Если бы я работал сегодня в AMD, то молчал бы сейчас как рыба и ссылался на этот statement в лучшем случае :)
Вы меня убедили, что возможно. Но я думаю, что на загруженной машине — маловероятно, слишком большой шум от других процессов в TLB. Но может это просто то, что я работал в основном с embedded.
Насчет «получить достаточно большой квант времени» — это зависит от конкретной установки. Если идет трафик по сети, то как-то неочевидно. С другой стороны этот трафик в основном в ядре обрабатываться будет.
В общем выглядит как зависящее от ситуации — если в системе есть что-то, еще работающее, то попытка использовать задержку TLB ненадежна, кэш более устойчив. С другой стороны 400 циклов на перезагрузку TLB элемента конечно дают больше шансов отловить.
На Интеле перегрузка CR3 приводит к очистке вретрипроцессорного массива TLB, который тоже иногда коротко называют кэшем TLB. Естественно, в CR3 заносят что-то, что не дает маппинга в ядро от пользователя даже если игнорировать биты разрешения/запрета доступа. Это сбивает meltdown логику.
Я вообще-то сам мерял, на MIPS-ах, там много меньше, чем 400 циклов. Но теперь понятно, почему Интел такой тормозной на переключении контекстов. Я думал это только на i7 core, но в статье упоминается Core 2…
Насчет вероятности — я трассировал загрузки TLB и число cache miss (опять на MIPS). Число промахов обращения к кэшу конечно много больше, но если поделить числа на размер кэша (1K строк) и на размер массива TLB (64 строки), то обновление конкретной строки кэша случается реже, чем элемента TLB, по крайней мере на Linux/Android.
Это не играет особой роли — не вышло сейчас, может выйти потом, на другом процессоре или другом коде — баг то есть, просто не дотянули по времени выполнения. Можно поиграться на multithreading и/или различных блокировках и т.п.
Честно скажу — патч не видел, просто прочитал рекомендации Интел (см выше), параграф 3.2 Branch Target Injection Mitigation. Для текущего железа они расписывают «retpoline» как
«software replaces indirect near jump and call instructions with a code sequence that includes pushing the target of the branch in question onto the stack and then executing a Return (RET) instruction to jump to that location...»
Может, конечно, интеллы чего-то не понимают в программировании, но рекомендации однозначны, и они потребуют разблокировать этот стэк для выполнения.
Кэш грузится строкой. У разных процессоров она разного размера, но обычно не больше 265 байт. Это определяется шириной шины процессора к памяти и сколько слов DDR тащится за одно обращение и сколько банков памяти.
С кэшем проще, так как из-за бОльшего размера вероятность, что процесс получения как-то собъется — меньше. И потом, для измерения времени доступа кэша — это доступ из памяти в кэш (довольно долго), а для перегрузки TLB — из кэша в TLB (довольно быстро). Выгнать из TLB еще можно, но прочистить TLB из кэша сложно, надо вытеснять весь кэш, так как адрес таблиц памяти неясен.
Интел предлагает вставлять LFENCE после условного перехода для фикса Варианта-1, и использовать команды PUSH + RET вместо перехода по регистру. Вроде LLVM/gcc уже даже патч есть.
Что касается PCID, то это очевидная оптимизация, но не везде и надо смотреть на общий случай если взвешивать др. варианты.
Я еще смотрел на возможность анализировать user код после exception и очищать строку кэша/TLB, но этот вариант, хотя и быстр по части потерь производительности, не пригоден, так как атака будет быстро реверснута — будет поиск очищеной строки кэша или TLB, увы.
Вы уж извините, год назад могли рассказать, а теперь это вопрос сильно крут с точки зрения денег.
Я могу предложить несколько вариантов, почему это у AMD не срабатывает, но в текущей ситуации просто придется принять к сведению — «не работает».
«Variant Three Rogue Data Cache Load Zero AMD vulnerability due to AMD architecture differences.»
Вариант 3 — meltdown. Остальное — догадка, чем отличается AMD.
Насчет «получить достаточно большой квант времени» — это зависит от конкретной установки. Если идет трафик по сети, то как-то неочевидно. С другой стороны этот трафик в основном в ядре обрабатываться будет.
Код PoC использует задержку кэша.
Насчет вероятности — я трассировал загрузки TLB и число cache miss (опять на MIPS). Число промахов обращения к кэшу конечно много больше, но если поделить числа на размер кэша (1K строк) и на размер массива TLB (64 строки), то обновление конкретной строки кэша случается реже, чем элемента TLB, по крайней мере на Linux/Android.
Может, конечно и не выйти ничего.
«software replaces indirect near jump and call instructions with a code sequence that includes pushing the target of the branch in question onto the stack and then executing a Return (RET) instruction to jump to that location...»
Может, конечно, интеллы чего-то не понимают в программировании, но рекомендации однозначны, и они потребуют разблокировать этот стэк для выполнения.