Память только для выполнения (XOM) для двоичных файлов AArch64

Разделы исполняемого кода для двоичных файлов системы AArch64 по умолчанию помечены как доступные только для выполнения (нечитаемые) в целях усиления защиты от атак с повторным использованием кода «точно в срок». Код, который смешивает данные и код вместе, а также код, который целенаправленно проверяет эти разделы (без предварительного перераспределения сегментов памяти как читаемые), больше не работает. Приложения с целевым SDK 10 (уровень API 29 или выше) будут затронуты, если приложение попытается прочитать в памяти разделы кода системных библиотек с поддержкой только памяти (XOM) без предварительной пометки раздела как доступного для чтения.

Чтобы в полной мере воспользоваться преимуществами этого смягчения, необходима поддержка как оборудования, так и ядра. Без этой поддержки смягчение последствий может быть реализовано лишь частично. Общее ядро ​​Android 4.9 содержит соответствующие исправления для обеспечения полной поддержки на устройствах ARMv8.2.

Выполнение

Двоичные файлы AArch64, созданные компилятором, предполагают, что код и данные не перемешаны. Включение этой функции не оказывает негативного влияния на производительность устройства.

Для кода, который должен выполнять преднамеренный самоанализ памяти в своих исполняемых сегментах, рекомендуется вызывать mprotect для сегментов кода, требующих проверки, чтобы сделать их читаемыми, а затем удалять читаемость после завершения проверки.
Эта реализация приводит к тому, что чтение в сегменты памяти, помеченные как доступные только для выполнения, приводит к ошибке сегментации ( SEGFAULT ). Это может произойти в результате ошибки, уязвимости, смешивания данных с кодом (буквальное объединение) или преднамеренного самоанализа памяти.

Поддержка устройств и влияние

Устройства с более ранним оборудованием или более ранними ядрами (ниже 4.9) без необходимых исправлений могут не полностью поддерживать эту функцию или не использовать ее преимущества. Устройства без поддержки ядра могут не обеспечивать пользовательский доступ к памяти, предназначенной только для выполнения, однако код ядра, который явно проверяет, доступна ли страница для чтения, все равно может применять это свойство, например, process_vm_readv() .

Флаг ядра CONFIG_ARM64_UAO должен быть установлен в ядре, чтобы гарантировать, что ядро ​​уважает страницы пользовательской области, помеченные только для выполнения. Устройства более ранних версий ARMv8 или устройства ARMv8.2 с отключенным переопределением доступа пользователя (UAO) могут не полностью извлечь из этого выгоду и по-прежнему могут читать страницы, доступные только для выполнения, с помощью системных вызовов.

Рефакторинг существующего кода

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

Рукописную сборку, возможно, придется реорганизовать для разделения констант из локального пула.

Примеры:

Двоичные файлы, созданные компилятором Clang, не должны иметь проблем с смешиванием данных в коде. Если включен код, созданный коллекцией компиляторов GNU (GCC), (из статической библиотеки), проверьте выходной двоичный файл, чтобы убедиться, что константы не были объединены в разделы кода.

Если необходим самоанализ кода в разделах исполняемого кода, сначала вызовите mprotect чтобы пометить код как читаемый. Затем, после завершения операции, снова вызовите mprotect , чтобы пометить его как нечитаемый.

Включение

Только выполнение включено по умолчанию для всех 64-битных двоичных файлов в системе сборки.

Отключение

Вы можете отключить только выполнение на уровне модуля, для всего дерева подкаталогов или глобально для всей сборки.

XOM можно отключить для отдельных модулей, которые не подлежат рефакторингу или которым необходимо прочитать их исполняемый код, установив для переменных LOCAL_XOM и xom значение false .

// Android.mk
LOCAL_XOM := false

// Android.bp
cc_binary { // or other module types
   ...
   xom: false,
}

Если в статической библиотеке отключена память только для выполнения, система сборки применяет это ко всем зависимым модулям этой статической библиотеки. Вы можете переопределить это, используя xom: true, .

Чтобы отключить память только для выполнения в определенном подкаталоге (например, foo/bar/), передайте значение XOM_EXCLUDE_PATHS .

make -j XOM_EXCLUDE_PATHS=foo/bar

Альтернативно вы можете установить переменную PRODUCT_XOM_EXCLUDE_PATHS в конфигурации вашего продукта.

Вы можете глобально отключить двоичные файлы, предназначенные только для выполнения, передав ENABLE_XOM=false в команду make .

make -j ENABLE_XOM=false

Проверка

Для памяти, предназначенной только для выполнения, не существует CTS или проверочных тестов. Вы можете вручную проверить двоичные файлы, используя readelf и проверив флаги сегментов.