Авторы:
(1) Зейн Вайсман, Вустерский политехнический институт, Вустер, Массачусетс, США {[email protected]};
(2) Томас Айзенбарт, Университет Любека Любек, Шотландия, Германия {[email protected]};
(3) Торе Тиманн, Любекский университет, Любек, SH, Германия {[email protected]};
(4) Берк Сунар, Вустерский политехнический институт, Вустер, Массачусетс, США {[email protected]}.
Виртуальная машина на базе ядра Linux (KVM) [29] представляет собой абстракцию функций аппаратной виртуализации, таких как Intel VT-x или AMD-V, которые доступны в современных процессорах. Для поддержки почти собственного выполнения в ядро Linux добавлен гостевой режим в дополнение к существующему режиму ядра и пользовательскому режиму. В гостевом режиме Linux KVM переводит оборудование в режим аппаратной виртуализации, который копирует привилегии кольца 0 и кольца 3.[1]
При использовании KVM виртуализация ввода-вывода выполняется в основном в пользовательском пространстве процессом, создавшим виртуальную машину, называемым VMM или гипервизором, в отличие от более ранних гипервизоров, которые обычно требовали отдельного процесса гипервизора [41]. Гипервизор KVM предоставляет каждой гостевой виртуальной машине собственную область памяти, отдельную от области памяти процесса, создавшего гостевую машину. Это справедливо для гостей, созданных как из пространства ядра, так и из пространства пользователя. Каждая виртуальная машина сопоставляется с процессом на хосте Linux, и каждый виртуальный процессор, назначенный гостю, является потоком в этом хост-процессе. Процесс гипервизора пользовательского пространства виртуальной машины выполняет системные вызовы к KVM только тогда, когда требуется привилегированное выполнение, сводя к минимуму переключение контекста и уменьшая поверхность атаки ядра виртуальной машины. Помимо повышения производительности всех видов приложений, эта конструкция позволила разработать облегченные гипервизоры, которые особенно полезны для изолированной программной среды отдельных программ и поддержки облачных сред, в которых одновременно работает множество виртуальных машин.
Все более популярной моделью облачных вычислений становятся бессерверные вычисления, в которых CSP управляет масштабируемостью и доступностью серверов, на которых выполняется пользовательский код. Одна из реализаций бессерверных вычислений называется «функция как услуга» (FaaS). В этой модели пользователь облака определяет функции, которые вызываются по мере необходимости через интерфейс прикладного программирования (API) поставщика услуг (отсюда и название «функция как услуга»), а CSP управляет распределением ресурсов на сервере, который выполняет функция пользователя (отсюда и название «бессерверные вычисления» — пользователь не управляет сервером). Аналогичным образом, вычисления «контейнер как услуга» (CaaS) запускают контейнеры, переносимые пакеты среды выполнения, по требованию. Централизованное управление серверами FaaS и CaaS экономически привлекательно как для CSP, так и для пользователей. CSP может управлять рабочей нагрузкой своих пользователей по своему усмотрению, оптимизировать эксплуатационные расходы и внедрять гибкие цены, при которых пользователи платят за время выполнения, которое они используют. Пользователю не нужно беспокоиться о проектировании или управлении серверной инфраструктурой, что снижает затраты на разработку и передает затраты на обслуживание CSP с относительно небольшой и предсказуемой скоростью.
Поставщики FaaS и CaaS используют различные системы для управления запущенными функциями и контейнерами. Контейнерные системы, такие как Docker, Podman и LXD, предоставляют удобный и легкий способ упаковки и запуска изолированных приложений в любой среде. Однако по сравнению с виртуальными машинами, используемыми во многих более традиционных формах облачных вычислений, контейнеры обеспечивают меньшую изоляцию и, следовательно, меньшую безопасность. В последние годы крупные поставщики услуг связи представили микровиртуальные машины, которые поддерживают традиционные контейнеры с облегченной виртуализацией для дополнительной безопасности. [1, 55] Эффективность аппаратной виртуализации с помощью KVM и облегченная конструкция микроVM означает, что код в виртуализированных, контейнерных или контейнероподобных системах может выполняться почти так же быстро, как невиртуализированный код, и с накладными расходами, сопоставимыми с традиционным контейнером.
Firecracker [1] — это микровиртуальная машина, разработанная AWS для изоляции каждой рабочей нагрузки AWS Lambda FaaS и AWS Fargate CaaS в отдельной виртуальной машине. Он поддерживает только гостей Linux на хостах x86 или ARM Linux-KVM и предоставляет ограниченное количество устройств, доступных гостевым системам. Эти ограничения позволяют Firecracker быть очень легким по размеру своей кодовой базы и расходу памяти для работающей виртуальной машины, а также очень быстро загружаться и завершать работу. Кроме того, использование KVM облегчает требования Firecracker, поскольку некоторые функции виртуализации выполняются системными вызовами ядра, а операционная система хоста управляет виртуальными машинами как стандартными процессами. Из-за небольшой базы кода, написанной на Rust, Firecracker считается очень безопасным, хотя в более ранних версиях были выявлены недостатки безопасности (см. CVE-2019-18960). Интересно, что в официальном документе Firecracker говорится, что микроархитектурные атаки входят в сферу действия его модели злоумышленника [1], но в нем отсутствует подробный анализ безопасности или специальные меры противодействия микроархитектурным атакам, помимо общих рекомендаций по конфигурации безопасной системы для гостевого и хостового ядра. В документации Firecracker есть рекомендации по безопасности системы [8], включающие конкретный список контрмер, который мы рассмотрим в разделе 2.6.1.
В 2018 году атака Meltdown [32] показала, что данные, к которым был получен спекулятивный доступ, могут быть выведены за пределы границ безопасности путем кодирования их в побочный канал кэша. Вскоре это привело к целому классу подобных атак, известных как выборка микроархитектурных данных (MDS), включая Fallout [14], Rogue In-flight Data Load (RIDL) [50], TSX Asynchronous Abort (TAA) [50] и Зомбилоад [46]. Все эти атаки следуют одной и той же общей схеме использования спекулятивного выполнения:
(1) Жертва запускает программу, которая обрабатывает секретные данные, и секретные данные проходят через кеш или буфер ЦП.
(2) Злоумышленник запускает специально выбранную инструкцию, которая заставит ЦП ошибочно предсказать, что потребуются секретные данные. ЦП передает секретные данные команде злоумышленника.
(3) Пересылаемые секретные данные используются в качестве индекса для чтения памяти в массиве, к которому злоумышленник имеет право доступа, в результате чего определенная строка этого массива кэшируется.
(4) ЦП завершает проверку данных и решает, что секретные данные были перенаправлены неправильно, и возвращает состояние выполнения до того, как они были перенаправлены, но состояние кэша не возвращается. (5) Злоумышленник исследует весь массив, чтобы определить, какая строка была закеширована; индекс этой строки — это значение секретных данных.
Исходная уязвимость Meltdown была нацелена на пересылку кэша и позволяла извлекать данные таким образом из любого адреса памяти, который присутствовал в кэше. Атаки MDS нацелены на меньшие и более конкретные буферы в микроархитектуре ядра и, таким образом, составляют родственный, но отдельный класс атак, защита от которых существенно отличается. В то время как Meltdown нацелен на основную память, которая обновляется относительно нечасто и используется всеми ядрами, потоками и процессами, атаки MDS, как правило, нацелены на буферы, которые являются локальными по отношению к ядрам (хотя иногда совместно используются несколькими потоками) и обновляются чаще во время выполнения.
2.4.1 Базовые варианты MDS . На рис. 1 показаны основные известные пути атак MDS на процессоры Intel, а также названия, данные различным вариантам компанией Intel и исследователями, которые сообщили о них. В более широком смысле Intel классифицирует уязвимости MDS в своих процессорах по конкретному буферу, из которого спекулятивно пересылаются данные, поскольку эти буферы, как правило, используются для ряда различных операций. Уязвимости RIDL MDS можно разделить на микроархитектурную выборку данных порта загрузки (MLPDS) для вариантов, которые просачиваются из порта загрузки ЦП, и микроархитектурную выборку данных заполнения буфера (MFBDS) для вариантов, которые просачиваются из LFB ЦП. В том же духе Intel называет уязвимость Fallout Microarchitectural Store Buffer Data Sampling (MSBDS), поскольку она связана с утечкой данных из буфера хранилища. Выборка векторных регистров (VRS) — это вариант MSBDS, предназначенный для данных, обрабатываемых векторными операциями при прохождении через буфер хранилища. Обход VERW использует ошибку в
исправления микрокода для MFBDS, который загружает устаревшие и потенциально секретные данные в LFB. Основной механизм утечки тот же, и байпас VERW можно считать частным случаем MFBDS. Выборка вытеснения данных L1 (L1DES) — это еще один особый случай MFBDS, когда данные, удаленные из кэша данных L1, проходят через LFB и становятся уязвимыми для атаки MDS. Примечательно, что L1DES — это случай, когда злоумышленник может фактически инициировать присутствие секретных данных в ЦП (путем их удаления), тогда как другие атаки MDS напрямую полагаются на процесс-жертву, обращающийся к секретным данным, чтобы перенести их в нужный буфер ЦП.
2.4.2 Медуза. Medusa [37] — это категория атак MDS, классифицированная Intel как варианты MLPDS [25]. Уязвимости Medusa используют несовершенные алгоритмы сопоставления с образцом, используемые для спекулятивного объединения хранилищ в буфере объединения записи (WC) процессоров Intel. Intel считает, что буфер WC является частью порта загрузки, поэтому Intel классифицирует эту уязвимость как случай MLPDS. Существует три известных варианта Medusa, каждый из которых использует разные особенности буфера объединения записи, чтобы вызвать спекулятивную утечку:
Индексация кэша: ошибочная загрузка спекулятивно объединяется с более ранней загрузкой с соответствующим смещением строки кэша.
Невыровненная пересылка от хранилища к загрузке: допустимое хранилище, за которым следует зависимая загрузка, которая вызывает ошибку смещения памяти, приводит к пересылке случайных данных из WC.
Shadow REP MOV : ошибочная инструкция REP MOV, за которой следует зависимая загрузка, приводит к утечке данных другого REP MOV.
2.4.3 Асинхронное прерывание TSX. Аппаратная уязвимость TSX Asynchronous Abort (TAA) [24] обеспечивает другой механизм спекуляций для проведения MDS-атаки. В то время как стандартные атаки MDS получают доступ к ограниченным данным со стандартным предполагаемым выполнением, TAA использует транзакцию атомарной памяти, реализованную TSX. Когда транзакция в атомарной памяти сталкивается с асинхронным прерыванием, например, из-за того, что другой процесс считывает строку кэша, помеченную для использования транзакцией, или из-за того, что транзакция обнаруживает ошибку, все операции в транзакции откатываются до архитектурного состояния, существовавшего до ее запуска. Однако во время этого отката инструкции внутри транзакции, которые уже начали выполнение, могут продолжить спекулятивное выполнение, как на шагах (2) и (3) других MDS-атак. TAA влияет на все процессоры Intel, поддерживающие TSX, а в случае некоторых новых процессоров, на которые не влияют другие атаки MDS, средства смягчения MDS или специфичные для TAA смягчения (например, отключение TSX) должны быть реализованы в программном обеспечении для защиты от TAA [24].
2.4.4 Смягчения. Хотя уязвимости класса Meltdown и MDS используют низкоуровневые микроархитектурные операции, их можно устранить с помощью исправлений встроенного ПО микрокода на наиболее уязвимых процессорах.
Изоляция таблицы страниц. Исторически таблицы страниц ядра включались в таблицы страниц процессов пользовательского уровня, чтобы процесс пользовательского уровня мог выполнять системные вызовы ядра с минимальными издержками. Изоляция таблицы страниц (впервые предложенная Груссом и др. как KAISER [19]) отображает только минимально необходимую память ядра в таблицу пользовательских страниц и вводит вторую таблицу страниц, доступную только ядру. Поскольку пользовательский процесс не может получить доступ к таблице страниц ядра, доступ ко всей памяти ядра, кроме небольшой и специально выбранной части, прекращается до того, как они достигнут кэшей нижнего уровня, где начинается атака Meltdown.
Перезапись буфера. Атаки MDS, направленные на буферы центрального процессора, требуют более низкоуровневой и более целенаправленной защиты. Intel представила обновление микрокода, которое перезаписывает уязвимые буферы при очистке кэша данных первого уровня (L1d) (частая цель атак по побочному каналу синхронизации кэша) или выполнении инструкции VERW [25]. Затем ядро может защитить от атак MDS, вызывая перезапись буфера при переключении на ненадежный процесс.
Защита от перезаписи буфера нацелена на атаку MDS на ее источник, но, мягко говоря, несовершенна. Процессы остаются уязвимыми для атак со стороны одновременно работающих потоков на одном и том же ядре, когда включен SMT (поскольку оба потока используют уязвимые буферы без фактического изменения активного процесса в любом потоке). Более того, вскоре после обновления микрокода перезаписи исходного буфера команда RIDL обнаружила что на некоторых процессорах Skylake буферы были перезаписаны устаревшими и потенциально конфиденциальными данными [50] и оставались уязвимыми даже при включенных средствах защиты и отключенном SMT. Тем не менее, другие процессоры уязвимы для атак TAA, но не для атак MDS без TAA, и не получили обновления микрокода перезаписи буфера и поэтому требуют полного отключения TSX для предотвращения атак MDS [20, 24].
2.5 Призрак
В 2018 году Ян Хорн и Пол Кохер [30] независимо друг от друга сообщили о первых вариантах Spectre. С тех пор было обнаружено множество различных вариантов Spectre [22, 30, 31, 33] и подвариантов [10, 13, 16, 28, 52]. Призрачные атаки заставляют ЦП спекулятивно обращаться к памяти, которая архитектурно недоступна, и переносить данные в архитектурное состояние. Таким образом, все варианты Spectre состоят из трех компонентов [27]:
Первый компонент — это гаджет Spectre, который спекулятивно выполняется. Варианты Spectre обычно разделяются по источнику неверного прогноза, который они используют. Результат условного прямого перехода, например, прогнозируется с помощью таблицы истории шаблонов (PHT). Неверные прогнозы PHT могут привести к спекулятивному обходу проверки границ для инструкций загрузки и сохранения [13, 28, 30]. Цель ветвления непрямого перехода прогнозируется с помощью целевого буфера ветвления (BTB). Если злоумышленник может повлиять на результат неверного предсказания BTB, то возможны спекулятивные атаки с возвратно-ориентированным программированием [10, 13, 16, 30]. То же самое верно и для прогнозов, обслуживаемых буфером стека возврата (RSB), который предсказывает адреса возврата во время выполнения инструкций возврата [13, 31, 33]. Недавние результаты показали, что некоторые современные процессоры используют BTB для прогнозирования адреса возврата в случае переполнения RSB [52]. Еще одним источником атак Spectre является прогнозирование зависимостей между хранилищем и загрузкой. Если ошибочно прогнозируется, что загрузка не зависит от предыдущего хранилища, она спекулятивно выполняется на устаревших данных, что может привести к спекулятивному обходу хранилища [22]. Все эти гаджеты по умолчанию недоступны для использования, но зависят от двух других компонентов, обсуждаемых сейчас.
Второй компонент — то, как злоумышленник контролирует входы в вышеупомянутые гаджеты. Злоумышленники могут иметь возможность определять входные значения гаджета непосредственно через пользовательский ввод, содержимое файла, сетевые пакеты или другие архитектурные механизмы. С другой стороны, злоумышленники могут иметь возможность временно вводить данные в гаджет посредством внедрения значения загрузки [12] или внедрения значения с плавающей запятой [42]. Злоумышленники могут успешно контролировать входные данные гаджета, если они могут влиять на то, к каким данным или инструкциям осуществляется доступ или выполнение во время окна спекуляций.
Третий компонент — это скрытый канал, который используется для перевода спекулятивного состояния микроархитектуры в состояние архитектуры и, следовательно, для вывода данных, к которым спекулятивно получен доступ, в постоянную среду. Скрытые каналы кэша [39, 40, 54] применимы, если код жертвы осуществляет временный доступ к памяти в зависимости от спекулятивно доступных секретных данных [30]. Если доступ к секрету осуществляется спекулятивно и загружается в буфер ядра, злоумышленник может полагаться на канал на основе MDS [14, 46, 50] для временной передачи отфильтрованных данных в поток злоумышленника, где данные передаются в архитектурный поток. состояние, например, через скрытый канал кэша. И последнее, но не менее важное: если жертва выполняет код в зависимости от секретных данных, злоумышленник может узнать секрет, наблюдая за конфликтом портов [3, 11, 18, 43, 44].
2.5.1 Смягчения. Для смягчения последствий различных вариантов Spectre было разработано множество контрмер. Конкретный вариант Spectre фактически отключается, если удален один из трех обязательных компонентов. Злоумышленник, не контролирующий входы в гаджеты Spectre, вряд ли сможет успешно провести атаку. То же самое верно, если скрытый канал трансформации спекулятивного состояния в архитектурное недоступен. Но поскольку это обычно трудно гарантировать, контрмеры Spectre в основном направлены на предотвращение неверных прогнозов. Вставка инструкций lfence перед критическими разделами кода отключает спекулятивное выполнение после этой точки и, следовательно, может использоваться в качестве общей контрмеры. Но из-за высоких затрат на производительность были разработаны более конкретные контрмеры. Противодействия Spectre-BTB включают Retpoline [48] и обновления микрокода, такие как IBRS, STIBP или IBPB [23]. Spectre-RSB и Spectre-BTB-via-RSB можно устранить, заполнив RSB значениями для перезаписи вредоносных записей и предотвращения переполнения RSB или установив обновления микрокода IBRS. Эффект Spectre-STL можно смягчить с помощью обновления микрокода SSBD [23]. Еще один радикальный способ предотвратить вмешательство злоумышленника в общие буферы прогнозирования ветвей — отключить SMT. Отключение SMT эффективно распределяет аппаратные ресурсы прогнозирования ветвей между одновременными арендаторами за счет значительной потери производительности.
Firecracker специально создан для бессерверных и контейнерных приложений [1] и в настоящее время используется AWS Fargate CaaS и Lambda FaaS. В обеих этих моделях обслуживания Firecracker является основной системой изоляции, которая поддерживает каждую отдельную задачу Fargate или событие Lambda. Обе эти модели обслуживания также предназначены для выполнения очень большого количества относительно небольших и кратковременных задач. AWS перечисляет требования к проектированию системы изоляции, которая в конечном итоге стала Firecracker, следующим образом:
Изоляция : запуск нескольких функций на одном и том же оборудовании должен быть безопасным, защищенным от повышения привилегий, раскрытия информации, скрытых каналов и других рисков.
Накладные расходы и плотность. Должна быть возможность запуска тысяч функций на одной машине с минимальными потерями.
Производительность: функции должны работать так же, как и в исходном виде. Производительность также должна быть согласованной и изолированной от поведения соседей на том же оборудовании.
Совместимость : Lambda позволяет функциям содержать произвольные двоичные файлы и библиотеки Linux. Они должны поддерживаться без изменений кода или перекомпиляции.
Быстрое переключение: должна быть возможность запускать новые функции и быстро очищать старые.
Мягкое распределение: должна быть возможность перераспределять ресурсы ЦП, памяти и других ресурсов, при этом каждая функция потребляет только те ресурсы, которые ей необходимы, а не те ресурсы, на которые она имеет право. [1]
Нас особенно интересуют требования изоляции , и мы подчеркиваем, что микроархитектурные атаки объявлены в рамках модели угроз Firecracker. Страница «Дизайн» в общедоступном репозитории AWS Firecracker Git подробно описывает модель изоляции и предоставляет полезную диаграмму, которую мы воспроизводим на рисунке 2. Эта диаграмма в основном относится к защите от повышения привилегий. Самый внешний уровень защиты — это джейлер, который использует методы изоляции контейнеров для ограничения доступа Firecracker к ядру хоста во время работы VMM и других компонентов управления.
Firecracker как потоки одного процесса в пользовательском пространстве хоста. В процессе Firecracker рабочая нагрузка пользователя выполняется в других потоках. Потоки рабочей нагрузки выполняют гостевую операционную систему виртуальной машины и все программы, работающие на гостевой машине. Запуск пользовательского кода в гостевой виртуальной машине ограничивает его прямое взаимодействие с хостом заранее запланированным взаимодействием с KVM и определенными частями потоков управления Firecracker. Таким образом, с точки зрения ядра хоста VMM и виртуальная машина, включая пользовательский код, выполняются в одном и том же процессе. Именно по этой причине AWS утверждает, что каждая виртуальная машина находится в одном процессе. Но поскольку виртуальная машина изолирована с помощью методов аппаратной виртуализации, пользовательский код, гостевое ядро и VMM работают в отдельных адресных пространствах. Таким образом, гостевой код не может архитектурно или временно получить доступ к адресам памяти VMM или гостевого ядра, поскольку они не отображаются в адресном пространстве гостя. Оставшаяся поверхность микроархитектурных атак ограничена атаками MDS, которые приводят к утечке информации из внутренних буферов ЦП, игнорируя границы адресного пространства, и атаками Spectre, когда злоумышленник манипулирует предсказанием ветвей других процессов для самостоятельной утечки информации.
Не показанная на рисунке 2, но не менее важная для модели угроз AWS изоляция функций друг от друга при совместном использовании оборудования, особенно в свете требований мягкого распределения . Помимо того факта, что компрометация ядра хоста может поставить под угрозу безопасность любых гостей, микроархитектурные атаки, нацеленные на оборудование хоста, также могут напрямую угрожать пользовательскому коду. Поскольку один процесс Firecracker содержит все необходимые потоки для запуска виртуальной машины с пользовательской функцией, мягкое выделение может быть просто выполнено операционной системой хоста [1]. Это означает, что поверх изоляции виртуальных машин используются стандартные системы изоляции процессов Linux.
2.6.1 Рекомендации по безопасности фейерверка. Документация Firecracker также рекомендует следующие меры предосторожности для защиты от микроархитектурных побочных каналов [8]:
• Отключить SMT
• Включить изоляцию таблицы страниц ядра.
• Отключить объединение кам-страниц ядра.
• Используйте ядро, скомпилированное с защитой Spectre-BTB (например, IBRS и IBPB на x86).
• Проверьте меры по смягчению последствий Spectre-PHT.
• Включить смягчение последствий L1TF. • Включить смягчение последствий Spectre-STL.
• Используйте память с помощью средства защиты Rowhammer.
• Отключите обмен или используйте безопасный обмен.
Этот документ доступен на arxiv под лицензией CC BY-NC-ND 4.0 DEED.
[1] Виртуализированные кольца 0 и 3 являются одной из основных причин, по которым достигается почти нативное исполнение кода.