Расширение тегов памяти вооружения

В Arm v9 представлено расширение Arm Memory Tagging Extension (MTE), аппаратная реализация тегированной памяти.

На высоком уровне MTE помечает каждое выделение/освобождение памяти дополнительными метаданными. Он назначает тег ячейке памяти, которую затем можно связать с указателями, ссылающимися на эту ячейку памяти. Во время выполнения ЦП проверяет, что указатель и теги метаданных совпадают при каждой загрузке и сохранении.

В Android 12 ядро ​​и аллокатор памяти кучи пользовательского пространства могут дополнять каждое выделение метаданными. Это помогает обнаружить ошибки использования после освобождения и переполнения буфера, которые являются наиболее распространенным источником ошибок безопасности памяти в наших кодовых базах.

Режимы работы МТЕ

МТЕ имеет три режима работы:

  • Синхронный режим (SYNC)
  • Асинхронный режим (ASYNC)
  • Асимметричный режим (ASYMM)

Синхронный режим (SYNC)

Этот режим оптимизирован для правильности обнаружения ошибок по сравнению с производительностью и может использоваться как точный инструмент обнаружения ошибок, когда приемлемы более высокие издержки производительности. При включении MTE SYNC действует как смягчение безопасности. При несоответствии тегов процессор немедленно прерывает выполнение и завершает процесс с SIGSEGV (код SEGV_MTESERR ) и полной информацией о доступе к памяти и адресе сбоя.

Мы рекомендуем использовать этот режим во время тестирования в качестве альтернативы HWASan/KASAN или в производстве, когда целевой процесс представляет собой уязвимую поверхность атаки. Кроме того, когда режим ASYNC указал на наличие ошибки, точный отчет об ошибке можно получить, используя API среды выполнения для переключения выполнения в режим SYNC.

При работе в режиме SYNC распределитель Android записывает трассировки стека для всех выделений и освобождений и использует их для предоставления лучших отчетов об ошибках, которые включают объяснение ошибки памяти, такой как использование после освобождения или переполнение буфера, а также трассировки стека соответствующих событий памяти. Такие отчеты предоставляют больше контекстной информации и упрощают отслеживание и исправление ошибок.

Асинхронный режим (ASYNC)

Этот режим оптимизирован для производительности, а не для точности отчетов об ошибках, и может использоваться для обнаружения ошибок безопасности памяти с низкими накладными расходами.
При несовпадении тегов процессор продолжает выполнение до ближайшей записи ядра (например, системного вызова или прерывания таймера), где он завершает процесс с помощью SIGSEGV (код SEGV_MTEAERR ) без записи адреса ошибки или доступа к памяти.
Мы рекомендуем использовать этот режим в производстве на хорошо протестированных кодовых базах, где известно, что плотность ошибок безопасности памяти низкая, что достигается за счет использования режима SYNC во время тестирования.

Асимметричный режим (ASYMM)

Дополнительная функция в Arm v8.7-A, режим асимметричного MTE, обеспечивает синхронную проверку чтения памяти и асинхронную проверку записи памяти с производительностью, аналогичной режиму ASYNC. В большинстве ситуаций этот режим является улучшением по сравнению с режимом ASYNC, и мы рекомендуем использовать его вместо ASYNC, когда он доступен.

По этой причине ни один из API, описанных ниже, не упоминает асимметричный режим. Вместо этого ОС можно настроить так, чтобы она всегда использовала асимметричный режим при запросе асинхронного режима. Для получения дополнительной информации см. раздел «Настройка предпочтительного уровня MTE для конкретного ЦП».

MTE в пользовательском пространстве

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

Включить MTE с помощью системы сборки

Как свойство всего процесса, MTE управляется настройкой времени сборки основного исполняемого файла. Следующие параметры позволяют изменять эту настройку для отдельных исполняемых файлов или для целых подкаталогов в исходном дереве. Эта настройка игнорируется в библиотеках или любой цели, которая не является ни исполняемым файлом, ни тестом.

1. Включение MTE в Android.bp ( пример ) для конкретного проекта:

Режим МТЕ Параметр
Асинхронный MTE
  sanitize: {
  memtag_heap: true,
  }
Синхронный МТЕ
  sanitize: {
  memtag_heap: true,
  diag: {
  memtag_heap: true,
  },
  }

или в Android.mk:

Режим МТЕ Параметр
Asynchronous MTE LOCAL_SANITIZE := memtag_heap
Synchronous MTE LOCAL_SANITIZE := memtag_heap
LOCAL_SANITIZE_DIAG := memtag_heap

2. Включение MTE в подкаталоге в исходном дереве с использованием переменной продукта:

Режим МТЕ Включить список Исключить список
асинхронный PRODUCT_MEMTAG_HEAP_ASYNC_INCLUDE_PATHS MEMTAG_HEAP_ASYNC_INCLUDE_PATHS PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS MEMTAG_HEAP_EXCLUDE_PATHS
синхронизировать PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS MEMTAG_HEAP_SYNC_INCLUDE_PATHS

или

Режим МТЕ Параметр
Асинхронный MTE MEMTAG_HEAP_ASYNC_INCLUDE_PATHS
Синхронный МТЕ MEMTAG_HEAP_SYNC_INCLUDE_PATHS

или указав путь исключения исполняемого файла:

Режим МТЕ Параметр
Асинхронный MTE PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS MEMTAG_HEAP_EXCLUDE_PATHS
Синхронный МТЕ

Пример (аналогично использованию PRODUCT_CFI_INCLUDE_PATHS )

  PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS=vendor/$(vendor)
  PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS=vendor/$(vendor)/projectA \
                                    vendor/$(vendor)/projectB

Включить MTE с помощью свойств системы

Указанные выше параметры сборки можно переопределить во время выполнения, установив следующее системное свойство:

arm64.memtag.process.<basename> = (off|sync|async)

Где basename обозначает базовое имя исполняемого файла.

Например, чтобы настроить /system/bin/ping или /data/local/tmp/ping на использование асинхронного MTE, используйте adb shell setprop arm64.memtag.process.ping async .

Включить MTE с помощью переменной среды

Еще один способ переопределить настройки сборки для собственных процессов (не приложений) — определить переменную среды: MEMTAG_OPTIONS=(off|sync|async) Если определены и переменная среды, и системное свойство, переменная имеет приоритет.

Включить MTE для приложений

Если не указано иное, MTE по умолчанию отключен, но приложения, желающие использовать MTE, могут сделать это, установив android:memtagMode под тегом <application> или <process> в AndroidManifest.xml .

android:memtagMode=(off|default|sync|async)

При установке в теге <application> атрибут влияет на все процессы, используемые приложением, и может быть переопределен для отдельных процессов путем установки тега <process> .

Для экспериментов можно использовать изменения совместимости , чтобы задать значение по умолчанию атрибута memtagMode для приложения, которое не указывает никакого значения в манифесте (или указывает default ).
Их можно найти в меню System > Advanced > Developer options > App Compatibility Changes в меню глобальных настроек. Установка NATIVE_MEMTAG_ASYNC или NATIVE_MEMTAG_SYNC включает MTE для конкретного приложения.
Альтернативно это можно сделать с помощью команды am следующим образом:

$ adb shell am compat enable NATIVE_MEMTAG_[A]SYNC my.app.name

Создайте образ системы MTE

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

Мы настоятельно рекомендуем включить MTE в синхронном режиме для всех собственных двоичных файлов во время разработки.

SANITIZE_TARGET=memtag_heap SANITIZE_TARGET_DIAG=memtag_heap m

Как и любую переменную в системе сборки, SANITIZE_TARGET можно использовать в качестве переменной среды или параметра make (например, в файле product.mk ).
Обратите внимание, что это включает MTE для всех собственных процессов, но не для приложений (которые являются ответвлениями zygote64 ), для которых MTE можно включить, следуя инструкциям выше .

Настройте предпочтительный уровень MTE для конкретного ЦП

На некоторых ЦП производительность MTE в режимах ASYMM или даже SYNC может быть аналогична производительности ASYNC. Это делает целесообразным включение более строгих проверок на этих ЦП, когда запрашивается менее строгий режим проверки, чтобы получить преимущества обнаружения ошибок более строгих проверок без ухудшения производительности.
По умолчанию процессы, настроенные для работы в режиме ASYNC, будут работать в режиме ASYNC на всех ЦП. Чтобы настроить ядро ​​для запуска этих процессов в режиме SYNC на определенных ЦП, значение sync должно быть записано в запись sysfs /sys/devices/system/cpu/cpu<N>/mte_tcf_preferred во время загрузки. Это можно сделать с помощью сценария init. Например, чтобы настроить ЦП 0-1 для запуска процессов режима ASYNC в режиме SYNC, а ЦП 2-3 для использования режима ASYMM, в предложение init сценария init поставщика можно добавить следующее:

  write /sys/devices/system/cpu/cpu0/mte_tcf_preferred sync
  write /sys/devices/system/cpu/cpu1/mte_tcf_preferred sync
  write /sys/devices/system/cpu/cpu2/mte_tcf_preferred asymm
  write /sys/devices/system/cpu/cpu3/mte_tcf_preferred asymm

Надгробия из процессов режима ASYNC, запущенных в режиме SYNC, будут содержать точную трассировку стека местоположения ошибки памяти. Однако они не будут включать трассировку стека выделения или освобождения. Эти трассировки стека доступны только в том случае, если процесс настроен на работу в режиме SYNC.

int mallopt(M_THREAD_DISABLE_MEM_INIT, level)

где level равен 0 или 1.
Отключает инициализацию памяти в malloc и избегает изменения тегов памяти, если это не требуется для корректности.

int mallopt(M_MEMTAG_TUNING, level)

где level :

  • M_MEMTAG_TUNING_BUFFER_OVERFLOW
  • M_MEMTAG_TUNING_UAF

Выбирает стратегию распределения тегов.

  • Значение по умолчанию — M_MEMTAG_TUNING_BUFFER_OVERFLOW .
  • M_MEMTAG_TUNING_BUFFER_OVERFLOW - включает детерминированное обнаружение ошибок линейного переполнения и недополнения буфера путем назначения отдельных значений тегов смежным выделениям. Этот режим имеет немного сниженный шанс обнаружения ошибок использования после освобождения, поскольку для каждого расположения памяти доступна только половина возможных значений тегов. Пожалуйста, имейте в виду, что MTE не может обнаружить переполнение в пределах одной гранулы тега (выровненный фрагмент по 16 байт) и может пропустить небольшие переполнения даже в этом режиме. Такое переполнение не может быть причиной повреждения памяти, поскольку память в пределах одной гранулы никогда не используется для нескольких выделений.
  • M_MEMTAG_TUNING_UAF — включает независимо рандомизированные теги для равномерной ~93% вероятности обнаружения как пространственных (переполнение буфера), так и временных (использование после освобождения) ошибок.

Помимо описанных выше API, опытным пользователям может быть полезно знать следующее:

  • Установка аппаратного регистра PSTATE.TCO может временно подавить проверку тегов ( пример ). Например, при копировании диапазона памяти с неизвестным содержимым тегов или устранении узкого места производительности в горячем цикле.
  • При использовании M_HEAP_TAGGING_LEVEL_SYNC обработчик сбоев системы предоставляет дополнительную информацию, такую ​​как трассировки стека выделения и освобождения. Эта функциональность требует доступа к битам тега и включается путем передачи флага SA_EXPOSE_TAGBITS при установке обработчика сигнала. Любой программе, которая устанавливает свой собственный обработчик сигнала и делегирует неизвестные сбои системному, рекомендуется делать то же самое.

MTE в ядре

Чтобы включить MTE-ускоренный KASAN для ядра, настройте ядро ​​с CONFIG_KASAN=y , CONFIG_KASAN_HW_TAGS=y . Эти конфигурации включены по умолчанию в ядрах GKI, начиная с Android 12-5.10 .
Это можно контролировать во время загрузки с помощью следующих аргументов командной строки:

  • kasan=[on|off] - включить или отключить KASAN (по умолчанию: on )
  • kasan.mode=[sync |async ] - выбор между синхронным и асинхронным режимом (по умолчанию: sync )
  • kasan.stacktrace=[on|off] — собирать ли трассировки стека (по умолчанию: on )
    • Для сбора трассировки стека также требуется stack_depot_disable=off .
  • kasan.fault=[report|panic] — только ли печатать отчет или также паниковать ядро ​​(по умолчанию: report ). Независимо от этой опции проверка тегов отключается после первой сообщенной ошибки.

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

Мы настоятельно рекомендуем использовать режим ASYNC в производстве. Это обеспечивает инструмент с низкими накладными расходами для обнаружения наличия ошибок безопасности памяти в процессе, а также дополнительную глубокую защиту. После обнаружения ошибки разработчик может использовать API среды выполнения для переключения в режим SYNC и получить точную трассировку стека от выборочного набора пользователей.

Мы настоятельно рекомендуем настроить предпочтительный уровень MTE для конкретного ЦП для SoC. Режим Asymm обычно имеет те же характеристики производительности, что и ASYNC, и почти всегда предпочтительнее его. Небольшие ядра с последовательным выполнением часто показывают схожую производительность во всех трех режимах и могут быть настроены на предпочтение SYNC.

Разработчики должны проверять наличие сбоев, проверяя /data/tombstones , logcat или отслеживая конвейер DropboxManager поставщика на наличие ошибок конечного пользователя. Для получения дополнительной информации об отладке собственного кода Android см. информацию здесь .

Компоненты платформы с поддержкой MTE

В Android 12 ряд критически важных для безопасности системных компонентов используют MTE ASYNC для обнаружения сбоев конечного пользователя и для работы в качестве дополнительного уровня глубокой защиты. Эти компоненты:

  • Сетевые демоны и утилиты (за исключением netd )
  • Bluetooth, SecureElement, NFC HAL и системные приложения
  • statsd демон
  • system_server
  • zygote64 (чтобы разрешить приложениям использовать MTE)

Эти цели были выбраны на основе следующих критериев:

  • Привилегированный процесс (определяется как процесс, имеющий доступ к чему-либо, чего не имеет домен SELinux unprivileged_app)
  • Обрабатывает ненадежные входные данные ( Правило двух )
  • Приемлемое замедление производительности (замедление не создает видимой для пользователя задержки)

Мы призываем поставщиков включить MTE в производство для большего количества компонентов, следуя критериям, указанным выше. Во время разработки мы рекомендуем тестировать эти компоненты с использованием режима SYNC, чтобы обнаружить легко исправляемые ошибки и оценить влияние ASYNC на их производительность.
В будущем Android планирует расширить список системных компонентов, на которых поддерживается MTE, руководствуясь характеристиками производительности будущих аппаратных разработок.