Diagnosing ARMv8.5 Memory Tagging Extension Tag-Check Faults on AArch64
A diagnostic guide for resolving ARMv8.5 Memory Tagging Extension (MTE) tag-check faults on AArch64, covering ESR analysis, pointer tag loss, and silicon errata.
28 Sept 2026, 16:31 UTC

Recognizable Condition
A Tag Check Fault (TCF) occurs when the processor detects a mismatch between the tag stored in the pointer's upper byte and the tag associated with the physical memory location being accessed. This manifests as a synchronous abort. To identify this condition, inspect the Exception Syndrome Register (ESR_ELx); a TCF is confirmed when bit 0 (TCF) is set. The Fault Status Code (FSC) will be 0x20 for an instruction abort or 0x24 for a data abort. The Fault Address Register (FAR_ELx) contains the virtual address that triggered the mismatch.
Cause and Diagnostic Table
| Observed Symptom | Likely Cause | Key Evidence |
|---|---|---|
| ESR_ELx.TCF=1, FSC=0x20/0x24, FAR_ELx in user-space | Software-generated pointer lost its Upper Byte Tag | Pointer casts to uintptr_t, arithmetic overflows, missing -mbranch-protection |
| Abort in region explicitly allocated as untagged | MTE enabled for process but region is untagged | prctl(PR_GET_TAGGED_ADDR_CTRL) result, mmap flags |
| Abort on specific core revision despite valid software | Silicon errata (e.g., ARM errata 1655431) | CPU part/revision from /proc/cpuinfo, vendor errata sheet |
| MTE faults on hardware lacking MTE support | Kernel configured with CONFIG_ARM64_MTE=y on unsupported CPU | /proc/cpuinfo missing 'mte' flag |
Ordered Diagnostic Checks
- Confirm Exception Type: Read ESR_ELx from the fault handler. Verify bit 0 (TCF) is 1 and check if the FSC is 0x20 (instruction) or 0x24 (data).
- Verify Hardware Support: Run
as a user with read permissions. The output must contain thegrep -i mte /proc/cpuinfomteflag. If absent, the hardware does not support MTE. - Check Kernel Configuration: Verify the kernel was built with MTE support by checking
or inspectingzcat /proc/config.gz | grep CONFIG_ARM64_MTE/boot/config-$(uname -r). It must showCONFIG_ARM64_MTE=y. - Inspect Process Tag Control: In the target process, call
. A non-zero return confirms the kernel is managing tags for this process.prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0) - Review Pointer Logic: Audit source code for casts between pointers and integer types narrower than
uintptr_t. Check for pointer arithmetic that may overflow into the tag space (bits 56-63). - Cross-Reference Silicon Errata: Extract the CPU part and revision from
/proc/cpuinfo. Compare these against the SoC vendor's errata list for known spurious MTE faults.
Fixes Tied to Findings
Software Tag Loss
- Replace narrowing casts (e.g., to
unsigned longon 32-bit compat) withintptr_toruintptr_t. - Recompile with
-mbranch-protection=standardto enable automatic tag injection and-moutline-atomicsif using atomic outlines. - If interoperability requires stripping tags, wrap the access by disabling MTE for the process:
.prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0)
Untagged Region Access
- Ensure memory is mapped with
MAP_TAGGEDif tagging is required. - For regions that must remain untagged, disable MTE globally via the boot parameter
mte=off(note: this removes protection for all processes).
Silicon Errata
- Apply vendor workarounds, such as inserting a
DSB SYfollowed by anISBinstruction before the memory access. - If the erratum is core-specific, disable MTE on the affected core via
cpuhotplug.
Kernel Misconfiguration
- If the CPU lacks MTE support, rebuild the kernel with
CONFIG_ARM64_MTE=n.
Escalation Criteria
If the fault persists after applying software fixes and verifying errata, escalate to the silicon vendor or ARM. Provide the following data:
- Register Dump: ESR_ELx, ELR_ELx, FAR_ELx, and the tag bits (56-63) of the fault address.
- System Context: Output of
uname -a,/proc/cpuinfo(part and revision), and the kernel.config. - Workload: A minimal reproducible example or the specific workload triggering the fault.
Practical Verification
To verify the MTE diagnostic path, you can create a minimal test program. Allocate memory using malloc, apply a tag using __builtin_arm_sttag, and then intentionally clear the upper byte of the pointer before dereferencing it. Run this under perf record -e arm64_mte_tag_check_fault ./test. A successful test will record a sample with ESR_ELx.TCF set.
Limitations: Disabling MTE via prctl or boot parameters masks genuine memory-safety bugs. Always limit disablement to the smallest possible scope (e.g., a specific process) to maintain system security.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.