Разделы исполняемого кода для системных двоичных файлов 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
и проверив флаги сегментов.