MTE dropped from Pixel 11: how the hardware memory tagging is structured and at which layer the chain breaks

On August 29, GrapheneOS announced that the port to Pixel 11 had reached an intermediate state and would not go further. The wording in the post is extremely specific: «We’re unable to complete the port due to lack of support for ARM hardware memory tagging in software, firmware and near certainly hardware» — there is no hardware memory tagging support in software or firmware, and almost certainly not in the hardware.

Pixel 11 was announced on August 12, 2026, and went on sale on the 20th. Before it, MTE worked on Pixel 8, 9 and 10 — effectively this is the only mass-market line of consumer devices where hardware memory tagging was not just a line in the ARM specification, but a turned-on and functioning feature.

Further content is not about phones. We’ll break down what layers MTE is built from, what it provides at each layer, and why a break at the lowest layer devalues all the layers above.

Important:

MTE is not «one more checkmark in security settings». It is the bottom layer, on top of which firmware, kernel, allocator, and applications operate. If it isn’t present in the silicon, you cannot enable it from above by any means.

Silicon: four bits for every sixteen bytes

According to the Linux kernel documentation, MTE appeared in ARMv8.5-based processors (Android documentation describes it as an Armv9 extension). The mechanism is simple: physical memory is sliced into 16-byte granules, and each granule has a 4-bit allocation tag. The second tag — the logical one — lives directly in the pointer, in bits 59–56 of the virtual address. On every access, the processor compares these two tags.

From there the cost is clear. Four bits per 128 bits of data means 3.125% of physical memory must be stored somewhere, plus changes in caches and memory access paths. There are no free features in silicon.

The second figure defines everything else: the tag is 4 bits, i.e., 16 possible values. The pointer to a freed or neighboring object has about one chance in sixteen to randomly match the granule’s tag and pass the check. MTE is a probabilistic protection, not a guarantee.

Firmware: support a little, but also enable it

Between silicon and the kernel there is a layer that is usually forgotten: SoC firmware and bootloader must report the presence of MTE and reserve memory for the tags. That’s why GrapheneOS’s wording lists three levels at once — «software, firmware and near certainly hardware».

Warning:

The official reason for the disappearance of MTE has not been announced. The theory about die area savings is a conjecture by GrapheneOS developers, stated in a Hacker News discussion; Google’s comments as of August 30, 2026 are not available. Note the phrase «near certainly»: even a project that hit the problem first does not claim 100% that the issue is hardware and not firmware.

Kernel: HWCAP2_MTE and three check modes

The kernel reports support through the flag HWCAP2_MTE, and the check mode is chosen by the process via prctl(PR_SET_TAGGED_ADDR_CTRL, ...).

Mode What happens on a miss Diagnostics Where applied
PR_MTE_TCF_NONE miss is ignored, default mode none code not prepared for tagging
PR_MTE_TCF_SYNC immediate SIGSEGV with code SEGV_MTESERR exact fault address, Android allocator adds allocation/free stacks debugging, vulnerable attack surfaces
PR_MTE_TCF_ASYNC SIGSEGV with code SEGV_MTEAERR on the closest entry into the kernel fault address is not preserved production, debugged code
asymmetric reads are checked like sync, writes like async same as sync on reads Armv8.7 and newer

The asymmetric mode cannot be requested directly: the kernel may choose it if the process requested both sync and async. The kernel’s priority order is async, then asymmetric, then sync, but the processor’s preferred mode overrides.

Check for MTE on the device with a single command:

adb shell grep mte /proc/cpuinfo
# Features : ... mte ...   — support is present
# lines missing            — MTE unavailable

On a normal aarch64 machine, this is the same file and the same line in Features. Internally, the state is read like this:

#include Allocator: who actually places the tags

The processor itself does not tag anything — it only compares. Tags are placed by the allocator, and that is where the real effect appears. In GrapheneOS this is hardened_malloc: the project’s function descriptions state “hardware memory tagging for slab allocations (128k and below) providing probabilistic detection of all use-after-free and inter-object overflows.” In the kernel, tagging is enabled in the main allocators — slab, page_alloc and non-executable vmalloc. In the Vanadium browser — in the main allocator.

The practical value here is not in abstract “security,” but in the fact that quiet memory corruption becomes a loud crash with an address and stack. According to the project developers in the same discussion, such triggers helped them find bugs in the upstream Linux kernel — meaning the effect propagates beyond the firmware itself.

## Application: two lines in the manifest

For application developers, tagging costs almost nothing. For native code, the mode is set by the manifest attribute:

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

Valid values are — off, default, sync, async; the attribute can also be attached to a single <process>. Outside the manifest there is a system property arm64.memtag.process.<basename> and the environment variable MEMTAG_OPTIONS with the same values. Stack tagging requires a rebuild with instrumentation and is available starting from Android 14 QPR3:

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

Practical minimum, if you have Pixel 8/9/10 and your native app: put android:memtagMode="sync" in app/src/debug/AndroidManifest.xml and run normal scenarios. The synchronous mode returns the crash address and the allocation/free stacks — this is the cheapest way to catch use-after-free, which otherwise would appear as a user-facing random crash.

The limits of the method: what tagging won’t reveal

Overflow within a single granule remains invisible: if an object occupies 20 bytes out of a 32-byte allocation, writing to the tail does not go beyond the same 16-byte granule, the tag does not change and the check passes. This is explicitly noted in Android documentation. Further — the aforementioned random tag match happens in about one in sixteen cases. The asynchronous mode, which is used in production for lower overheads, does not preserve the crash address: the fact of memory corruption you will see; the exact address you will not. And logical bugs, races, leaks and everything that happens in managed Java or Kotlin code are entirely outside its scope: MTE works with native heap and stack.

Security:

Memory tagging does not replace ASLR, sandboxing, or timely updates. It is an additional layer that makes exploiting use-after-free more costly and noticeable. The absence of MTE does not turn a device into a hole; its presence does not make it invulnerable.

What changes in practice

For most Pixel owners — almost nothing, and that is an important detail of the whole story. Google enables MTE narrowly: in the Advanced Protection guide it is described as “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” — meaning for supported apps and in enhanced protection mode, not system-wide by default. On-Pixel 10 and Pixel 11, in normal use, Android will behave the same.

The difference is critical where tagging is applied system-wide. For GrapheneOS, the dropout of the lower layer means that on new hardware the tags in the kernel, the hardened_malloc with hardware tagging, and the browser’s allocator protection all disappear at once. The port is not canceled — it is not completed, and there are no deadlines.

And a broader takeaway for those looking at ARM beyond phones: before planning memtag on an ARM server or single-board computer, perform the check from the kernel section. The presence of the line mte in Features is a question of the specific processor and its firmware, not the hardware generation year.

Similar analyses on the forum: 12 bits per second from a neighboring worker — about how a hardware feature becomes an attack surface, and Flipper Zero firmware yourself — about firmware layers on ARM.

Sources

Question:

Has anyone seen the string mte in /proc/cpuinfo on anything other than Pixel 8/9/10 — on an ARM server, single-board computer, laptop? And do you consider a probabilistic protection, where one miss out of sixteen goes unnoticed, a sufficient reason to keep it enabled in production?