Перейти к содержанию

Тегирование памяти в ARM: как работает MTE и почему новый Pixel остался без неё

Опубликовано
  • Админы
ARM MTE и Pixel 11
Тег занимает четыре бита и описывает шестнадцать байт памяти

Свежий флагман Google остался без функции, ради которой часть аудитории и покупала Pixel. 29 августа команда GrapheneOS объявила: работа над сборкой для Pixel 11 остановлена на полпути. Причину они назвали одной фразой — «We're unable to complete the port due to lack of support for ARM hardware memory tagging in software, firmware and near certainly hardware». Ни софт, ни прошивка тегирование памяти не поддерживают, и в кремнии его, судя по всему, тоже нет.

Продажи Pixel 11 стартовали 20 августа, анонс состоялся восемью днями раньше. Предыдущие три поколения — восьмое, девятое и десятое — оставались, по сути, единственным серийным потребительским железом, где тегирование памяти не значилось в спецификации ARM теоретически, а было доведено до рабочего состояния.

Телефоны тут интереснее как повод. Ниже — устройство самого механизма, его цена, его слабые места и ответ на вопрос, кого именно задевает пропажа.

❗ ГЛАВНОЕ

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

Пять слоёв MTE
Пять уровней, через которые проходит тегирование памяти

16 байт, 4 бита и одно сравнение

Расширение впервые описано для ядер архитектуры ARMv8.5 — так сказано в документации ядра Linux; материалы Android относят его к Armv9. Работает оно следующим образом. Вся физическая память разбивается на кусочки по шестнадцать байт, которые называются гранулами, и каждый такой кусочек получает собственную четырёхбитную метку. Ещё одна метка, логическая, прячется в самом указателе — под неё отведены биты с 59-го по 56-й виртуального адреса. Совпадение двух меток проверяется процессором на каждом доступе к памяти.

Проверка тега
Что сравнивается при каждом обращении в память

Посчитаем накладные расходы. На сто двадцать восемь бит полезных данных приходится четыре бита служебных, а это 3,125 % всей физической памяти, которые надо где-то разместить. Добавьте сюда доработку кэшей и тракта доступа к памяти — и станет понятно, что даром такая функция не достаётся.

Из размера метки следует и главное ограничение. Четыре бита дают шестнадцать вариантов, поэтому повисший или уехавший в соседний объект указатель примерно в одном случае из шестнадцати угадает метку гранулы и спокойно пройдёт контроль. Речь идёт о вероятностном барьере, а не о жёсткой гарантии.

Три режима и один флаг: взгляд со стороны ядра

О наличии поддержки ядро рассказывает флагом HWCAP2_MTE. Какой именно контроль включить, каждый процесс решает за себя вызовом prctl(PR_SET_TAGGED_ADDR_CTRL, ...).

РежимЧто происходит при промахеДиагностикаГде применяют
PR_MTE_TCF_NONEпромах игнорируется, это режим по умолчаниюнеткод, не готовый к разметке
PR_MTE_TCF_SYNCнемедленный SIGSEGV с кодом SEGV_MTESERRточный адрес сбоя, аллокатор Android добавляет стеки выделения и освобожденияотладка, уязвимые поверхности атаки
PR_MTE_TCF_ASYNCSIGSEGV с кодом SEGV_MTEAERR при ближайшем входе в ядроадрес сбоя не сохраняетсяпродакшн, отлаженный код
асимметричныйчтения проверяются как в sync, записи — как в asyncкак у sync на чтенияхArmv8.7 и новее

Запросить асимметричный вариант напрямую не получится. Он достаётся процессу как побочный результат: если тот попросил сразу синхронный и асинхронный контроль, ядро вправе выдать асимметричный. Собственный порядок предпочтений у ядра выглядит как асинхронный, асимметричный, синхронный, однако предпочтительный режим, настроенный на процессоре, перебивает этот список.

Узнать, есть ли поддержка на конкретном аппарате, можно одной строкой:

adb shell grep mte /proc/cpuinfo
# Features : ... mte ...   — поддержка есть
# строки нет               — MTE недоступна

Для любой машины на aarch64 проверка не отличается: тот же файл, та же строка в Features. Если состояние нужно узнать изнутри процесса, подойдёт такой фрагмент:

#include <sys/prctl.h>

int mode = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
bool mte_on = (mode != -1) && (mode & PR_MTE_TCF_MASK);

Прослойка, о которой забывают: загрузчик и прошивка

Между кристаллом и ядром есть ещё один уровень. Прошивке SoC и загрузчику полагается объявить о доступности механизма и зарезервировать физическую память под сами метки. Оттого в заявлении GrapheneOS и перечислены три уровня подряд: «software, firmware and near certainly hardware».

⚠️ ОСТОРОЖНО

Официального объяснения пропажи не публиковалось. Экономия площади кристалла — гипотеза, которую разработчики GrapheneOS озвучили в обсуждении на Hacker News; со стороны Google комментариев по состоянию на 30 августа 2026 года не поступало. Отдельного внимания заслуживает оборот «near certainly»: даже те, кто столкнулся с проблемой раньше всех, не берутся стопроцентно утверждать, что виновато железо, а не прошивка.

Метки расставляет вовсе не процессор

Задача процессора сводится к сравнению — раскладывать метки по гранулам должен аллокатор, и настоящий эффект появляется именно на этом уровне. У GrapheneOS роль аллокатора играет hardened_malloc, о котором в перечне возможностей проекта сказано: «hardware memory tagging for slab allocations (128k and below) providing probabilistic detection of all use-after-free and inter-object overflows». Внутри ядра метками пользуются slab, page_alloc и неисполняемый vmalloc, а в браузере Vanadium — основной аллокатор.

Толк от этого измеряется не абстрактной защищённостью. Незаметное повреждение памяти превращается в шумное падение, у которого есть и адрес, и стек вызовов. Разработчики проекта в том же треде рассказывали, что подобные срабатывания приводили их к ошибкам в апстримном ядре Linux, — выигрыш достаётся не только пользователям одной прошивки.

Со стороны приложения — один атрибут

Разработчику приложения подключение обходится почти бесплатно. Нативному коду в Android режим задают прямо в манифесте:

<application android:memtagMode="sync"
             tools:replace="android:memtagMode" />

Атрибут принимает значения off, default, sync и async, и повесить его допустимо не только на всё приложение, но и на конкретный <process>. Помимо манифеста существуют системное свойство arm64.memtag.process.<basename> и переменная окружения MEMTAG_OPTIONS, принимающие тот же набор значений. Метки на стеке — история отдельная: они требуют пересборки с инструментацией и работают начиная с Android 14 QPR3.

-fsanitize=memtag -fno-omit-frame-pointer -march=armv8-a+memtag

✅ КАК ПРАВИЛЬНО

Есть Pixel 8, 9 или 10 и собственный нативный код? Тогда стоит добавить android:memtagMode="sync" в app/src/debug/AndroidManifest.xml и просто погонять привычные сценарии. Синхронный контроль вернёт адрес сбоя вместе со стеками выделения и освобождения, а это самая дешёвая ловушка для use-after-free, которая иначе всплывёт у пользователя в виде «случайного» падения.

Где механизм перестаёт работать

Слепая зона номер один — переполнение внутри гранулы. Пусть объекту выделено тридцать два байта, а занимает он двадцать: запись в хвост не покидает пределов той же шестнадцатибайтовой гранулы, метка остаётся прежней, контроль проходит успешно. Об этом честно предупреждает документация Android. Вторая зона уже упоминалась — примерно одно случайное совпадение меток на шестнадцать попыток. Третья связана с асинхронным режимом: его и ставят в продакшн ради минимальных накладных расходов, но адрес сбоя он не сохраняет, так что факт повреждения вы увидите, а точку — нет. Наконец, гонки, утечки, логика и всё происходящее в управляемом коде на Java или Kotlin лежат за пределами компетенции механизма: он занимается нативными кучей и стеком.

🔒 БЕЗОПАСНОСТЬ

Ни песочницу, ни ASLR, ни регулярные обновления тегирование памяти не отменяет. Его роль — сделать эксплуатацию use-after-free затратнее и заметнее. Дырявым аппарат без него не становится, неуязвимым с ним — тоже.

Кому это действительно что-то меняет

Владелец обычного Pixel не заметит ничего, и деталь эта важна для понимания всей истории. Сама Google применяет механизм точечно: справка по Advanced Protection описывает его так — «Memory Tagging Extension (MTE): For supported apps, MTE will help prevent apps from corrupting memory. When MTE is on, you may experience slower device performance». Значит, речь о поддерживаемых приложениях в режиме усиленной защиты, а не о системной настройке по умолчанию. В обычном сценарии штатный Android на десятом и одиннадцатом Pixel ведёт себя одинаково.

Ощутимой потеря становится там, где метки применялись повсеместно. У GrapheneOS вместе с нижним уровнем на новом железе пропадают сразу три вещи: разметка внутри ядра, аппаратные метки в hardened_malloc и защита браузерного аллокатора. Отменённым порт не считается — он просто не завершён, и никаких сроков не названо.

Вывод, выходящий за рамки смартфонов: если memtag фигурирует в ваших планах на одноплатник или сервер с ARM, начните с проверки из раздела про ядро. Появится ли mte в списке Features, зависит от конкретного процессора и его прошивки, а не от свежести железа.


Источники

💬 ВОПРОС К СООБЩЕСТВУ

Попадалась ли кому-нибудь строка mte в /proc/cpuinfo за пределами Pixel 8, 9 и 10 — на сервере с ARM, одноплатнике, ноутбуке? И достаточный ли это повод держать защиту включённой в продакшне, если один промах из шестнадцати всё равно проходит незамеченным?

Featured Replies

No posts to show

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

Последние посетители 0

  • Ни одного зарегистрированного пользователя не просматривает данную страницу
Яндекс.Метрика

Account

Navigation

Поиск

Поиск

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.