Как смягчить призрак с помощью GCC и Clang (или LLVM в целом)

Microsoft добавила удобный /Qspectre к своему компилятору MSVC (хотя, похоже, это только (пытается) смягчить Spectre v1 на данный момент), что они будут обновляться с течением времени. Это очень приятно с точки зрения пользователей, просто включите этот флаг, и вы получите последнее и самое большое смягчение, которое у них есть.

С LLVM и GCC это выглядит несколько иначе. Я не думаю, что их смягчения официально выпущены.

LLVM должен получить флаг -mretpoline для компилятора, который смягчает Spectre v2 через возвратные батуты для косвенных вызовов.

GCC, с другой стороны, имеет исправления, которые добавляют три параметра компилятора для смягчения Spectre v2:

  • -mindirect-branch, который может быть установлен на thunk. Как я понимаю, это создает ретрополины для каждого косвенного вызова.
  • -mfunction-return, который может быть установлен на thunk. Я предполагаю, что это использует эти retpolines для каждого возврата функции, что может потребоваться для Skylake, потому что эти процессоры также могут прогнозировать возврат?
  • -mindirect-branch-register Используется ли регистр вместо стека для хранения адреса косвенного вызова?

Итак, я очень смущен. Какая опция компилятора смягчает то, что и в каких сценариях они необходимы для приложения пользовательского пространства?

Хорошо ли вообще включить их? Будут ли они также генерировать эти retpolines, если они скомпилированы для архитектуры процессора, которая даже не имеет какого-либо спекулятивного исполнения (например, микропроцессоров)?

Как насчет Spectre v1?

UPDATE:

Позвольте мне задать более точные вопросы:

  • Насколько я понимаю, что параметры компилятора исправляют?
  • Используются ли опции GCC повсюду или только для процессоров со спекулятивным исполнением?
  • Используются ли параметры LLVM повсюду или только для процессоров со спекулятивным исполнением?
  • Что именно смягчают эти параметры (полностью ли они смягчают призрак v2)?
  • Давайте рассмотрим все остальное, что я попросил, чтобы были дополнительные "бонусные" вопросы, которые хорошо знать, но не существенны для моего вопроса.

Ответ 1

Является ли мое понимание того, что параметры компилятора исправляют?

Я так думаю.

Используются ли параметры GCC повсюду или только для процессоров со спекулятивным исполнением?

До сих пор параметры были x86. Я не проверял, есть ли эквивалентные ARM-патчи, но в любом случае эти параметры будут по меньшей мере частично зависеть от архитектуры процессора.

Я только посмотрел на часть patches, но не похоже, что накладываются дополнительные проверки выполнения. Скорее, выбор команды изменяется, чтобы предотвратить бэкэнд от нежелательных косвенных переходов, если параметры установлены.

Таким образом, этот параметр не применяется к полностью несвязанным архитектурам, но не предпринимается никаких попыток выяснить, является ли конкретный процессор уязвимым во время выполнения. Обратите внимание, что большинство более известных x86-процессоров, проданных с ок. Pentium Pro действительно использует спекулятивное выполнение.

Что именно смягчают эти параметры (полностью ли они смягчают призрак v2)?

В основном они смягчают инъекцию целевой ветки (Spectre v2), гарантируя, что на соответствующий косвенный вызов не происходит спекуляция, контролируемая атакующим.

Репозиты достигают этого, используя команды возврата, чтобы перейти к целевому адресу, в котором используется другой предиктор ветки, который в основном помнит, откуда пришел последний вызов. Это управляется сгенерированным кодом, который выполняет инструкцию вызова перед инструкцией return, которая гарантирует, что спекулированное выполнение ударит в тупик, поместив инструкцию mfence после вызова. Подробнее см. этот ответ.

Включение инъекции ветки является проблемой, поскольку, как объяснено в Spectre Paper в разделе "Обсуждение 5.1", может быть много кода, отображаемого для злоумышленника. Дискуссия говорит о Windows, но я мог представить, что в Linux также должен быть код из разделяемых библиотек. Если эти кодовые адреса более рандомизированы, использование может быть сложнее, но я не буду рассчитывать на это без проверки. В частности, в ядре Linux содержится много кода, который может быть использован злоумышленником с возможностью впрыскивания произвольных цепей ветвления.

-mfunction-return

На первый взгляд кажется глупо защищать возврат, заменяя его более сложным возвратом, но согласно это сообщение от David Woodhouse опция была запрошена разработчиками ядра Linux, потому что при переполнении запоминаемых обратных адресов (в основном, скрытого стека, следующего за стеком вызовов) некоторые процессоры снова втягивают в глобальный отраслевой предсказатель, который может манипулировать злоумышленником. Поэтому ваше объяснение было правильным. Согласно тому же сообщению, этот флаг не был сразу использован ядром Linux. Я предполагаю, что влияние производительности будет значительным, так как доходность гораздо более распространена, чем другие косвенные отрасли, а специализированное предсказание обратной связи достигнет отличных показателей на практике.

-mindirect-branch-register

Я не совсем уверен, что смягчает -mindirect-branch-register. По-видимому, это необходимо в тестовом наборе вместе с другими вариантами, но я пока не смог найти объяснения. Также Xen использует эту опцию вместе с -mindirect-branch=thunk-extern, что означает, что они сами записывают сам код thunk и не позволяют компилятору сгенерировать его. Вопреки моему первоначальному предположению, это не имеет ничего общего с потенциальной спекуляцией, пока адрес загружен, поскольку это предназначено для использования с retpolines, которые предотвращают эту спекуляцию. В некоторых дискуссиях было упомянуто, что версия thunks, которые принимают целевой адрес в стеке, а не в регистре, первоначально имела конфликты с Intel Технология управления потоком управления потоком (CET). Я предполагаю, что, поскольку ретрополины используют возвращение необычным способом, CET предотвращал прыжки. Однако, согласно это обсуждение, эти проблемы, похоже, были решены, а на машинах, поддерживающих CET, доступны другие смягчения (IBRS_ALL) что позволяет заменять ретушированные штыри на косвенные прыжки снова. Я предполагаю, что этот вариант не поможет сам по себе.