Тег занимает четыре бита и описывает шестнадцать байт памяти
Свежий флагман 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 теоретически, а было доведено до рабочего состояния.
Телефоны тут интереснее как повод. Ниже — устройство самого механизма, его цена, его слабые места и ответ на вопрос, кого именно задевает пропажа.
❗ ГЛАВНОЕ
Тегирование памяти устроено как фундамент, а не как переключатель в меню безопасности. На него опираются загрузчик, ядро, аллокатор и прикладной код — все четыре уровня выше. Отсутствие фундамента ничем не компенсируется программно.
Пять уровней, через которые проходит тегирование памяти
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_ASYNC
SIGSEGV с кодом SEGV_MTEAERR при ближайшем входе в ядро
адрес сбоя не сохраняется
продакшн, отлаженный код
асимметричный
чтения проверяются как в sync, записи — как в async
как у sync на чтениях
Armv8.7 и новее
Запросить асимметричный вариант напрямую не получится. Он достаётся процессу как побочный результат: если тот попросил сразу синхронный и асинхронный контроль, ядро вправе выдать асимметричный. Собственный порядок предпочтений у ядра выглядит как асинхронный, асимметричный, синхронный, однако предпочтительный режим, настроенный на процессоре, перебивает этот список.
Узнать, есть ли поддержка на конкретном аппарате, можно одной строкой:
adb shell grep mte /proc/cpuinfo
# Features : ... mte ... — поддержка есть
# строки нет — MTE недоступна
Для любой машины на aarch64 проверка не отличается: тот же файл, та же строка в Features. Если состояние нужно узнать изнутри процесса, подойдёт такой фрагмент:
Прослойка, о которой забывают: загрузчик и прошивка
Между кристаллом и ядром есть ещё один уровень. Прошивке 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 режим задают прямо в манифесте:
Атрибут принимает значения off, default, sync и async, и повесить его допустимо не только на всё приложение, но и на конкретный <process>. Помимо манифеста существуют системное свойство arm64.memtag.process.<basename> и переменная окружения MEMTAG_OPTIONS, принимающие тот же набор значений. Метки на стеке — история отдельная: они требуют пересборки с инструментацией и работают начиная с Android 14 QPR3.
Есть 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, одноплатнике, ноутбуке? И достаточный ли это повод держать защиту включённой в продакшне, если один промах из шестнадцати всё равно проходит незамеченным?
Вы можете написать сейчас и зарегистрироваться позже.
Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.
Свежий флагман 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 теоретически, а было доведено до рабочего состояния.
Телефоны тут интереснее как повод. Ниже — устройство самого механизма, его цена, его слабые места и ответ на вопрос, кого именно задевает пропажа.
❗ ГЛАВНОЕ
Тегирование памяти устроено как фундамент, а не как переключатель в меню безопасности. На него опираются загрузчик, ядро, аллокатор и прикладной код — все четыре уровня выше. Отсутствие фундамента ничем не компенсируется программно.
16 байт, 4 бита и одно сравнение
Расширение впервые описано для ядер архитектуры ARMv8.5 — так сказано в документации ядра Linux; материалы Android относят его к Armv9. Работает оно следующим образом. Вся физическая память разбивается на кусочки по шестнадцать байт, которые называются гранулами, и каждый такой кусочек получает собственную четырёхбитную метку. Ещё одна метка, логическая, прячется в самом указателе — под неё отведены биты с 59-го по 56-й виртуального адреса. Совпадение двух меток проверяется процессором на каждом доступе к памяти.
Посчитаем накладные расходы. На сто двадцать восемь бит полезных данных приходится четыре бита служебных, а это 3,125 % всей физической памяти, которые надо где-то разместить. Добавьте сюда доработку кэшей и тракта доступа к памяти — и станет понятно, что даром такая функция не достаётся.
Из размера метки следует и главное ограничение. Четыре бита дают шестнадцать вариантов, поэтому повисший или уехавший в соседний объект указатель примерно в одном случае из шестнадцати угадает метку гранулы и спокойно пройдёт контроль. Речь идёт о вероятностном барьере, а не о жёсткой гарантии.
Три режима и один флаг: взгляд со стороны ядра
О наличии поддержки ядро рассказывает флагом
HWCAP2_MTE. Какой именно контроль включить, каждый процесс решает за себя вызовомprctl(PR_SET_TAGGED_ADDR_CTRL, ...).PR_MTE_TCF_NONEPR_MTE_TCF_SYNCSIGSEGVс кодомSEGV_MTESERRPR_MTE_TCF_ASYNCSIGSEGVс кодомSEGV_MTEAERRпри ближайшем входе в ядроЗапросить асимметричный вариант напрямую не получится. Он достаётся процессу как побочный результат: если тот попросил сразу синхронный и асинхронный контроль, ядро вправе выдать асимметричный. Собственный порядок предпочтений у ядра выглядит как асинхронный, асимметричный, синхронный, однако предпочтительный режим, настроенный на процессоре, перебивает этот список.
Узнать, есть ли поддержка на конкретном аппарате, можно одной строкой:
Для любой машины на aarch64 проверка не отличается: тот же файл, та же строка в
Features. Если состояние нужно узнать изнутри процесса, подойдёт такой фрагмент:Прослойка, о которой забывают: загрузчик и прошивка
Между кристаллом и ядром есть ещё один уровень. Прошивке 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 режим задают прямо в манифесте:
Атрибут принимает значения
off,default,syncиasync, и повесить его допустимо не только на всё приложение, но и на конкретный<process>. Помимо манифеста существуют системное свойствоarm64.memtag.process.<basename>и переменная окруженияMEMTAG_OPTIONS, принимающие тот же набор значений. Метки на стеке — история отдельная: они требуют пересборки с инструментацией и работают начиная с Android 14 QPR3.✅ КАК ПРАВИЛЬНО
Есть 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, одноплатнике, ноутбуке? И достаточный ли это повод держать защиту включённой в продакшне, если один промах из шестнадцати всё равно проходит незамеченным?TOP HOSTERS: KAMATERA (30 дней бесплатного теста!)
Универсальный хостер №1 - 4VPS.su (2Гб\с сервера) - 10% скидка на первый заказ или 15% бонус на первое пополнение