Внутренняя работа Призрака (v2) - PullRequest
0 голосов
/ 05 февраля 2019

Я немного прочитал о Spectre v2, и, очевидно, вы получите нетехнические объяснения.У Питера Кордеса есть более подробное объяснение , но оно не полностью раскрывает некоторые детали.Примечание: я никогда не проводил атаку Spectre v2, поэтому у меня нет опыта.Я только прочитал о теории.

Мое понимание Призрака v2 заключается в том, что вы делаете ошибочный прогноз непрямой ветви, например if (input < data.size).Если косвенный целевой массив (в котором я не слишком уверен в деталях - то есть, почему он отделен от структуры BTB) - который перепроверяется при декодировании для RIP непрямых ветвлений - не содержит прогноз, тогда онвставит новый прыжок RIP (выполнение ветви в конечном итоге вставит целевой RIP ветви), но пока он не знает целевой RIP прыжка, поэтому любая форма статического предсказания не будет работать.Насколько я понимаю, он всегда будет предсказывать, что он не будет принят для новых непрямых ветвей, и когда порт 6 в конечном итоге разработает целевой RIP перехода и прогнозирования, он откатится с помощью BOB и обновит ITA с правильным адресом перехода, а затем обновит локальный иглобальная отраслевая история регистрирует и насыщающие счетчики соответственно.

Хакеру необходимо обучить насыщающие счетчики, чтобы всегда предсказать взятый результат, который, я думаю, они делают, выполняя if(input < data.size) несколько раз в цикле, где input имеет значение, которое действительно меньше data.size (соответственно, перехват ошибок) и на последней итерации цикла сделайте input больше data.size (например, 1000);будет предсказано, что косвенная ветвь будет принята, и она перейдет к телу оператора if, в котором происходит загрузка кэша.

Оператор if содержит secret = data[1000] (определенный адрес памяти (data [1000]), которыйсодержит секретные данные, предназначенные для загрузки из памяти в кэш), затем они будут спекулятивно распределены в буфере загрузки.Предыдущая косвенная ветвь все еще находится в модуле выполнения ветвлений и ожидает завершения.

Я полагаю, что предпосылка заключается в том, что нагрузка должна быть выполнена (назначен буфер заполнения строки), прежде чем буферы загрузки сбрасываются при неправильном прогнозе.,Если ему уже был назначен буфер заполнения строки, то ничего не поделаешь.Имеет смысл, что нет механизма отмены выделения буфера заполнения строки, потому что буфер заполнения строки должен был бы отложиться перед сохранением в кэш после возвращения его в буфер загрузки.Это может привести к насыщению буферов заполнения строк, потому что вместо освобождения при необходимости (сохранение его там для скорости других загрузок по тому же адресу, но освобождение при отсутствии других доступных строчных буферов).Он не сможет освободить место до тех пор, пока не получит некоторый сигнал о том, что сброс не произойдет, что означает, что он должен остановиться для выполнения предыдущей ветви вместо того, чтобы немедленно сделать буфер заполнения строки доступным для хранилищ.другого логического ядра.Этот механизм сигнализации может быть сложным для реализации, и, возможно, он не приходил им в голову (предварительное мышление), и он также привел бы к задержке в том случае, если выполнение ветвлений занимает достаточно времени для зависания буферов заполнения строки, что может повлиять на производительность, т.е. еслиdata.size преднамеренно сбрасывается из кэша (CLFLUSH) перед тем, как последняя итерация цикла означает, что выполнение ветвления может занять до 100 циклов.

Я надеюсь, что мое мышление верно, но я не на 100%конечно.Если кому-то есть что добавить или исправить, пожалуйста, сделайте.

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

Иногда термин «BTB» используется вместе для обозначения всех буферов, используемых блоком прогнозирования ветвлений.Однако на самом деле существует несколько буферов, каждый из которых используется в каждом цикле для прогнозирования цели и направления.В частности, BTB используется для прогнозирования прямых ветвлений, ITB (косвенный целевой буфер) используется для прогнозирования косвенных ветвлений, за исключением возвратов, а RSB используется для прогнозирования возвратов.ITB также называется IBTB или косвенным целевым массивом.Все эти термины используются разными поставщиками и исследователями.Как правило, BTB используется для создания начальных прогнозов для всех видов команд ветвления, когда другие буферы отсутствуют.Но позже предиктор узнает больше о ветвях, и другие буферы вступают в игру.Если несколько динамических экземпляров одной и той же косвенной ветви имеют одну и ту же цель, то вместо ITB может также использоваться BTB.ITB гораздо точнее, когда одна и та же ветвь имеет несколько целей и предназначена специально для работы с такими ветвями.См .: Ветвление предсказания и выступления переводчиков - Не верь фольклору .Первым процессором Intel, в котором реализованы отдельные структуры BTB и ITB, является Pentium M. Все более поздние процессоры Intel Core имеют выделенные ITB.

Эксплойт Spectre V1 основан на обучении BTB с использованием атакующего.запрограммируйте так, чтобы, когда жертва выполняла ветвь, которая совмещала одну и ту же запись BTB, процессор обманчиво умело выполнял инструкции (называемые гаджетом) для утечки информации.Эксплойт Spectre V2 аналогичен, но вместо этого основан на обучении ITB.Принципиальное отличие состоит в том, что в V1 процессор неверно прогнозирует направление ветви, а в V2 процессор неверно прогнозирует target ветви (и, в случае условногокосвенная ветвь, направление тоже, потому что мы хотим, чтобы это было принято).В программах, которые интерпретируются, JIT-компилируются или используют динамический полиморфизм, может быть много косвенных ветвей (кроме возвратов).Конкретная непрямая ветвь никогда не может быть предназначена для перехода в какое-то место, но, неправильно обучив предиктора, она может быть сделана, чтобы прыгнуть куда угодно.Именно по этой причине V2 очень мощный;независимо от того, где находится гаджет и какие бы намеренные потоки управления программы не находились, вы можете выбрать одну из косвенных ветвей и заставить ее умозрительно перейти к гаджету.

Обратите внимание, что обычно это линейный адресцель статической прямой ветки остается неизменной на протяжении всего жизненного цикла программы.Есть только одна ситуация, когда это может быть не так: динамическая модификация кода.Так что, по крайней мере теоретически, эксплойт может быть разработан на основе target неправильного предсказания прямых ветвей.

Относительно утилизации LFB, я не очень понимаю, что вы говорите.Когда запрос на загрузку, который пропустил L1D, получает данные в LFB, данные немедленно передаются в обходное соединение конвейера.Должен быть способ определить, какой тип загрузки запросил эти данные.Возвращаемые данные должны быть помечены UOP ID загрузки.Источники мопов в RS, которые ожидают данные, представлены в виде идентификаторов моп нагрузок.Кроме того, запись ROB, в которой хранится загрузка, должна быть помечена как завершенная, чтобы ее можно было удалить, а в pre-SnB возвращенные данные необходимо записать в ROB.Если при очистке конвейера невыполненный запрос на загрузку в LFB не отменяется, и если идентификатор загрузки uop повторно использовался для некоторого другого uop, когда данные поступают, он может быть неправильно перенаправлен на все новые операции в настоящее время в конвейере,тем самым портит микроархитектурное состояние.Таким образом, должен быть способ гарантировать, что это не произойдет ни при каких обстоятельствах.Очень возможно отменить невыполненные запросы на загрузку и спекулятивные RFO при очистке конвейера, просто пометив все действительные записи LFB как «отмененные», просто чтобы данные не возвращались в конвейер.Тем не менее, данные все еще могут быть получены и заполнены в один или несколько уровней кэшей.Запросы в LFB идентифицируются физическими адресами с выравниванием строк.Возможны и другие варианты.

Я решил провести эксперимент, чтобы точно определить, когда LFB будут освобождены на Haswell.Вот как это работает:

Outer Loop (10K iterations):

Inner Loop (100 iterations):
10 load instructions to different cache lines most of which miss the L2.
LFENCE.
A sequence of IMULs to delay the resolution of the jump by 18 cycles.
Jump to inner.

3 load instructions to different cache lines.
LFENCE.
Jump to outer.

Чтобы это работало, необходимо отключить гиперпоточность и оба средства предварительной выборки L1, чтобы гарантировать, что мы владеем всеми 10 LFB L1.

Инструкции LFENCE гарантируют, что мы не исчерпаем LFB при выполнении на правильно предсказанном пути.Ключевая идея здесь заключается в том, что внутренний скачок будет неверно предсказан один раз за внешнюю итерацию, поэтому в LFB можно выделить до 10 нагрузок внутренней итерации, которые находятся на неверно предсказанном пути.Обратите внимание, что LFENCE предотвращает распределение нагрузок от более поздних итераций.Через несколько циклов внутренняя ветвь будет разрешена, и произойдет неправильное предсказание.Конвейер очищается, а внешний интерфейс извлекается для извлечения и выполнения команд загрузки во внешнем цикле.

Возможны два результата:

  • LFB, которые были выделены для нагрузок на неверно предсказанном пути, немедленно освобождаются как часть операции очистки конвейера и становятся доступными для других нагрузок.,В этом случае не будет остановок из-за недоступности LFB (подсчитывается с использованием L1D_PEND_MISS.FB_FULL).
  • LFB освобождаются только тогда, когда нагрузки обслуживаются независимо от того, были ли они на неверно предсказанном пути.

Когда во внутреннем цикле после внутреннего скачка есть три нагрузки, измеренное значение L1D_PEND_MISS.FB_FULL примерно равно числу внешних итераций.Это один запрос на итерацию внешнего цикла.Это означает, что когда три нагрузки на правильном пути передаются на L1D, нагрузки от неверно указанного пути все еще занимают 8 записей LFB, что приводит к событию заполнения FB для третьей загрузки.Это говорит о том, что нагрузка в LFB будет де-лакирована только тогда, когда нагрузка действительно завершится.

Если я добавлю менее двух загрузок во внешний цикл, в основном не будет событий FB full.Я заметил одну вещь: для каждой дополнительной нагрузки во внешнем контуре, превышающей три нагрузки, L1D_PEND_MISS.FB_FULL увеличивается примерно на 20 КБ вместо ожидаемых 10 КБ.Я думаю, что происходит то, что, когда запрос на загрузку UOP нагрузки выдается в L1D впервые, и все LFB используются, он отклоняется.Затем, когда LFB становится доступным, две нагрузки, ожидающие в буфере загрузки, отправляются на L1D, одна будет распределена в LFB, а другая будет отклонена.Таким образом, мы получаем два события LFB full на каждую дополнительную нагрузку.Однако, когда во внешнем цикле три нагрузки, только третья будет ожидать LFB, поэтому мы получаем одно событие на каждую итерацию внешнего цикла.По существу, буфер загрузки не может различить наличие одного LFB или двух LFB;он только узнает, что по крайней мере один LFB свободен, и поэтому он пытается отправить два запроса на загрузку одновременно, так как есть два порта загрузки.

0 голосов
/ 05 февраля 2019

Для веток некоторые похожи на jc .somewhere, когда ЦПУ действительно нужно только угадать, будет ли ветвь взята или нет, чтобы иметь возможность спекулировать по предполагаемому пути.Однако некоторые ветви похожи на jmp [table+eax*8], где может быть более 4 миллиардов возможных направлений, и для этих случаев ЦП должен угадать целевой адрес, чтобы можно было спекулировать по предполагаемому пути.Поскольку существуют очень разные типы ветвей, ЦП использует очень разные типы предикторов.

Для Spectre существует «мета-паттерн» - злоумышленник использует умозрительное выполнение, чтобы обманным путем заставить ЦП оставить информацию в чем-то, а затем извлечьинформация из чего-то.Существует множество возможностей для «чего-то» (кэши данных, кэши инструкций, TLB, целевой буфер ветвления, буфер направления ветвления, стек возврата, буферы объединения записи, ...), и, следовательно, существует множество возможных вариаций спектра (и не только«хорошо известные первые два варианта», которые были обнародованы в начале 2018 г.).

Для Spectre v1 (где «что-то» - это кэш данных) злоумышленнику необходимо каким-то образом обмануть ЦП и поместить данные вкэш данных (например, загрузка, а затем вторая загрузка, которая зависит от значения из первой загрузки, которое может быть выполнено умозрительно) и некоторый способ извлечения информации (очистить все в кэше, а затем использовать количество времени, в течение которого загружаетсятребуется, чтобы определить, как изменилось состояние кэша данных).

Для Spectre v2 (где «что-то» - буфер направления ветвления, который используется для таких инструкций, как jc .somewhere), атакующему нужен какой-то способ обмануть процессорв помещение данных в буфер направления ветвления (например, нагрузка и тЗатем в ветви, которая зависит от нагрузки, которая может выполняться спекулятивно) и каким-либо способом извлечения информации (предварительно установите буфер направления ветвления в известное состояние, затем используйте время, которое требуется ветви, чтобы определить, как состояниеизменен буфер направления ветвления).

Для всех возможных вариаций спектра, единственное, что важно (для защиты), это то, что может быть «чем-то» (и как предотвратить попадание информации в «»).что-то », или сбросить / перезаписать / уничтожить информацию, попавшую в« что-то »).Все остальное (конкретные детали одной из множества возможных реализаций кода для атаки на любой из множества возможных вариантов призрака) не имеет значения.

Неопределенная история призрака

Первоначальный Спектр (v1, с использованием тайминга кеша) был найден в 2017 году и публично объявлен в январе 2018 года. Это было похоже на прорыв плотины, и вскоре последовали несколько других вариантов (например, v2, с использованием предсказания ветвления).Эти ранние вариации привлекли много внимания.Примерно через 6 месяцев после этого было найдено множество других вариантов, но они не получили такой широкой огласки, и многие люди не знали (и до сих пор не знают) о них.Ко второй половине 2018 года люди (например, я) начали терять представление о том, какие варианты были доказаны (с помощью реализаций «доказательства концепции»), а какие еще не доказаны, и некоторые исследователи начали пытаться перечислять возможности и устанавливать соглашения об именах.для них.Лучший пример этого, который я видел до сих пор, это «Систематическая оценка атак и защит временного исполнения» (см. https://arxiv.org/pdf/1811.05441.pdf).

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

...