Что такое ретполин и как он работает?

чтобы смягчить раскрытие памяти ядра или перекрестного процесса (Spectre атаки), ядро Linux1 будет скомпилирован с новой опцией, -mindirect-branch=thunk-extern представил gcc для выполнения косвенных вызовов через так называемый retpoline.

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

Что такое ретполин и как это это предотвратит недавние атаки на раскрытие информации ядра?


1 это не специфично для Linux, однако-аналогичная или идентичная конструкция, похоже, используется как часть стратегии смягчения последствий на других ОС.

2 ответов


статьи упомянутый sgbj в комментариях, написанных полом Тернером из Google, объясняет следующее Более подробно, но я дам ему шанс:

насколько я могу собрать это вместе из ограниченной информации на данный момент, ретполин-это возвращение батут который использует бесконечный цикл, который никогда не выполняется, чтобы предотвратить спекуляцию ЦП на цели косвенного прыжка.

основной подход можно увидеть в ветвь ядра Энди Клин решения этой проблемы:

он представляет новый __x86.indirect_thunk вызов, который загружает цель вызова, чей адрес памяти (который я буду называть ADDR) хранится поверх стека и выполняет прыжок с помощью RET инструкция. Затем сам thunk вызывается с помощью NOSPEC_JMP / CALL макрос, который использовался для замены многих (если не всех) косвенных вызовов и прыжков. Макрос просто помещает цель вызова на стеке и задает обратный адрес правильно, при необходимости (обратите внимание на нелинейный поток управления):

.macro NOSPEC_CALL target
    jmp     1221f            /* jumps to the end of the macro */
1222:
    push    \target          /* pushes ADDR to the stack */
    jmp __x86.indirect_thunk /* executes the indirect jump */
1221:
    call    1222b            /* pushes the return address to the stack */
.endm

размещение call в конце концов необходимо так, что когда косвенный вызов закончен, поток управления продолжается за использованием NOSPEC_CALL макрос, поэтому его можно использовать вместо обычного call

сам удар выглядит следующим образом:

    call retpoline_call_target
2:
    lfence /* stop speculation */
    jmp 2b
retpoline_call_target:
    lea 8(%rsp), %rsp 
    ret

поток управления может немного запутаться здесь, поэтому позвольте мне уточните:

  • call нажимает указатель текущей инструкции (метка 2) на стек.
  • lea добавляет 8 к указатель стека, эффективно отбрасывая последнее четырехсловие, которое является последним обратным адресом (для метки 2). После этого верхняя часть стека снова указывает на реальный обратный адрес ADDR.
  • ret скачков *ADDR и сбрасывает указатель стека в начале вызова стек.

в конце концов, все это поведение практически эквивалентно прыжку непосредственно в *ADDR. Единственное преимущество, которое мы получаем, заключается в том, что предиктор ветви используется для операторов return (Return Stack Buffer, RSB) при выполнении call инструкция, предполагает, что соответствующий ret оператор перейдет к метке 2.

часть после метки 2 фактически никогда не выполняется, это просто бесконечный цикл, который теоретически заполнит конвейер инструкций с JMP инструкция. Используя LFENCE,PAUSE или, в более общем плане, инструкция, вызывающая остановку конвейера инструкций, останавливает CPU от потери энергии и времени на это спекулятивное выполнение. Это связано с тем, что в случае, если вызов retpoline_call_target вернется нормально,LFENCE будет следующей инструкции для выполнения. Это также то, что предсказатель ветвей будет предсказывать на основе исходного обратного адреса (метки 2)

цитата из руководства по архитектуре Intel:

инструкции, следующие за LFENCE, могут быть извлечены из памяти до LFENCE, но они не будут выполняться до завершения LFENCE.

обратите внимание, однако, что в спецификации никогда не упоминается, что LFENCE и PAUSE вызывают остановку трубопровода, поэтому я читаю немного между строками здесь.

теперь вернемся к вашему изначальному вопросу: Информация о памяти ядра раскрытие возможно из-за сочетания двух идей:

  • хотя спекулятивное исполнение должно быть свободным от побочных эффектов, когда спекуляция была неправильной,спекулятивное выполнение все еще влияет на иерархию кэша. Это означает, что при выполнении загрузки памяти спекулятивно, это все еще может привести к вытеснению строки кэша. Это изменение в иерархии кэша можно определить путем тщательного измерения времени доступа к памяти, которое сопоставлен с тем же набором кэша.
    Вы даже можете пропустить некоторые биты произвольной памяти, когда исходный адрес считываемой памяти был сам считан из памяти ядра.

  • косвенный предиктор ветви процессоров Intel использует только самые низкие 12 бит исходной инструкции, таким образом, легко отравить все 2^12 возможных историй прогнозирования с управляемыми пользователем адресами памяти. Они могут затем, когда косвенный скачок предсказан внутри ядра, быть спекулятивно выполняется с правами ядра. Используя боковой канал синхронизации кэша, вы можете, таким образом, утечка произвольной памяти ядра.

обновление: на список рассылки ядра, продолжается обсуждение, которое заставляет меня полагать, что ретполины не полностью смягчают Проблемы прогнозирования ветвей, так как когда буфер стека возврата (RSB) работает пустым, более поздние архитектуры Intel (Skylake+) возвращаются к уязвимому целевому буферу ветви (BTB):

Retpoline как стратегия смягчения меняет непрямые ветви на возврат, чтобы избежать использования прогнозов, которые исходят от BTB, так как они могут быть отравлен нападавшим. Проблема с Skylake+ заключается в том, что поток RSB возвращается к использованию BTB прогноз, который позволяет злоумышленнику взять под контроль спекуляции.


A retpoline предназначен для защиты против впрыска цели ветви (CVE-2017-5715) эксплуатировать. Это атака, в которой косвенная инструкция ветви в ядре используется для принудительного спекулятивного выполнения произвольного куска кода. Выбранный код - это "гаджет", который каким-то образом полезен злоумышленнику. Например, можно выбрать код, который будет пропускать данные ядра через то, как он влияет на кэш. Retpoline предотвращает этот эксплойт просто заменой все косвенные инструкции ветви с инструкцией возврата.

Я думаю, что ключ в retpoline-это просто часть "ret", которая заменяет косвенную ветвь инструкцией возврата, так что процессор использует предиктор стека возврата вместо предиктора эксплуатируемой ветви. Если простое нажатие и возврат инструкция есть-то код, что бы теоретически выполнил бы код функции вернутся в любом случае, не какой-то гаджет полезно злоумышленник. Основное преимущество части trampoline, по-видимому, заключается в поддержании стека возврата, поэтому, когда функция действительно возвращается к вызывающему объекту, это предсказывается правильно.

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

обратите внимание, что retpoline не предотвращает раскрытие информации ядра напрямую, он только предотвращает использование косвенных инструкций ветви для спекулятивного выполнения гаджета, который будет раскрывать информацию. Если злоумышленник может найти какие-то другие средства для спекулятивного выполнения гаджета, то ретполин не предотвращает атаку.

в статье Атаки Spectre: Эксплуатация Спекулятивное Исполнение Пауль Кохер, Даниэль Генкин, Даниэль Грасс, Вернер Хаас, Майк Гамбург, Мориц Липп, Стефан Мангард, Томас Прешер, Майкл Шварц и Юваль Яром дают следующий обзор того, как можно использовать косвенные ветви:

Использование Косвенных Ветвей. рисунок от возвратно-ориентированного программирования (ROP), в этом методе злоумышленник выбирает гаджет С адреса пространство жертвы и влияния жертва, чтобы выполнить гаджет спекулятивно. В отличие от ROP, злоумышленник не полагается на уязвимость в коде жертвы. Вместо этого, злоумышленник тренирует Отраслевая целевая буфера (БТБ) в mispredict ветку с косвенным ответвление инструкции на адрес гаджета, в результате чего спекулятивное исполнение гаджета. Хотя теоретически выполнил инструкции заброшены, их влияние на кэш отсутствует возвратившегося. Эти эффекты могут быть использованы гаджетом для утечки чувствительный информация. Мы покажем, как, при тщательном выборе гаджета, это метод может быть использован для чтения произвольной памяти у жертвы.

To mistrain в БТБ, злоумышленник находит виртуальный адрес гаджета в адресном пространстве жертвы затем выполняет косвенные ветви к этому адрес. Это обучение выполняется из адресного пространства атакующего, и не имеет значения, что находится по адресу гаджета в адресное пространство злоумышленника; все, что требуется это ветка для обучения филиалы использовать один и тот же виртуальный адрес. (В факт, пока злоумышленник обрабатывает исключения, атака может работать даже если нет кода, сопоставленного с виртуальным адресом гаджета в адресном пространстве злоумышленника.) Также нет необходимости в полном соответствие адреса источника филиала, используемого для обучения и адрес целевой ветви. Таким образом, злоумышленник имеет значительные гибкость в настройке обучение.

запись в блоге под названием чтение привилегированной памяти с боковым каналом команда Project Zero в Google предоставляет еще один пример того, как можно использовать целевую инъекцию филиала для создания рабочего эксплойта.