MIE / MTE — Memory Integrity Enforcement / Memory Tagging Extension
MTE là hardware mitigation mới nhất và mạnh nhất của Apple, triển khai từ iPhone 17 (A19) dưới tên MIE (Memory Integrity Enforcement). MTE detect heap corruption (UAF, overflow, type confusion) tại hardware level — biến phần lớn memory corruption bugs thành crash thay vì exploitable primitive.
Tham khảo: “Navigating the MTE Landscape: iOS Memory Protection Deep Dive” — Atlan Pinabel & Patrick Ventuzelo (FuzzingLabs), OffensiveCon 2026.
Tại Sao MTE Là Game-Changer
Trước MTE:
UAF bug → reallocate freed memory → type confusion → kread/kwrite
Heap overflow → corrupt adjacent object → controlled primitive
→ Hầu hết kernel exploits dựa vào memory corruption
Sau MTE:
UAF bug → pointer tag ≠ memory tag → FAULT (crash, không exploitable)
Heap overflow → cross boundary → different tag → FAULT
→ Memory corruption bugs trở nên RẤT KHÓ exploit
ARM MTE Cơ Bản (ARMv8.5, 2019)
Concept
MTE gắn 4-bit tag vào mỗi 16-byte granule của physical memory:
Pointer: 0x 0A 00FFFFF1234000
^^
Tag (4 bits, stored in bits [59:56])
Memory granule: Mỗi 16 bytes có 1 tag riêng
Stored trong "tag storage" (~3% of DRAM)
Mỗi memory access:
Hardware so sánh: pointer tag vs memory tag
Match → access allowed
Mismatch → TAG CHECK FAULT (sync hoặc async)
Tag Storage
Physical memory layout:
Low PA TagOffset_EL2 High PA
┌─────────────┬────────────────────────┬──────────────────┐
│ PHYS_SLIDE │ AVAILABLE │ TAG STORAGE │
│ Firmwares │ (covered by XNU │ (1/32 of DRAM) │
│ (SEP, TXM, │ vm_pages) │ │
│ SPTM, KC) │ │ │
└─────────────┴────────────────────────┴──────────────────┘
Tag storage = ~3% of DRAM (1 tag = 4 bits per 16-byte granule)
Tag storage protected by SPTM (typed as XNU_TAG_STORAGE)
MTE Instructions
| Instruction | Chức năng |
|---|---|
IRG Xd, Xn |
Insert Random tag Generation — tạo random tag |
GMI Xd, Xn, Xm |
Tag Mask — exclude specific tags |
STG [Xn] |
Store Allocation Tag — ghi tag vào tag storage |
LDG Xd, [Xn] |
Load Allocation Tag — đọc tag từ tag storage |
ADDG Xd, Xn, #imm, #tag |
Add with tag manipulation |
SUBG Xd, Xn, #imm, #tag |
Subtract with tag manipulation |
15 Usable Tag Values
4 bits → 16 possible values (0x0 - 0xF)
Tag 0x0 và 0xF là canonical (untagged)
→ 15 usable values: {1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E} + one of {0, F}
Adjacent allocations get DIFFERENT tags
→ Overflow vào allocation kế bên = tag mismatch = FAULT
EMTE — Enhanced MTE (ARMv8.9, 2022)
FEAT_MTE4 mở rộng MTE với:
- Canonical tag checking: tagged pointer không thể access untagged memory
- Tag permission: deny
STG/LDGqua untagged PTEs - Checked Pointer Arithmetic (FEAT_CPA, ARMv9.5): phát hiện pointer arithmetic bugs
Apple’s MIE (Memory Integrity Enforcement)
Deployment
- iPhone 17 (A19): First device with MTE/MIE
- M5 Macs: EMTE in synchronous mode only
- Tích hợp vào cả kernel allocators lẫn userland allocators
4 Thành Phần Của MIE
Apple's MIE (Memory Integrity Enforcement)
│
├── 1. (E)MTE hardware ← ARM instruction set
│ + Tag Confidentiality
│
├── 2. XNU integration ← Kernel-level MTE management
│
├── 3. Kernel allocator ← zalloc/kalloc MTE tagging
│
└── 4. User allocator ← libmalloc/libpas MTE support
Tag Confidentiality Enforcement
Apple đặc biệt quan tâm đến tag confidentiality — ngăn attacker biết tag values:
| Protection | Cơ chế |
|---|---|
| PRNG reseeding | Tag generation PRNG reseed tại mỗi context switch (PACGA_IRG_RESEED macro) |
| Tag storage protection | Tag storage pages typed XNU_TAG_STORAGE, protected bởi SPTM |
| Side-channel resistance | SoC designed to resist TikTag, StickyTag, Spectre V1 timing attacks |
XNU Integration
MTE Activation — Per-Process Decision
MTE được quyết định per-process tại exec time trong imgact_setup_sec():
Inheritance enabled?
├── YES → Enable MTE (mirror parent state)
└── NO
posix_spawn explicit enable?
├── YES → Enable MTE (through posix_spawn flags)
└── NO
hardened-process entitlement?
(Or platform && DriverKit)
├── YES → Enable MTE (through entitlements)
└── NO
AMFI opt-out MTE?
└── → Disable MTE
Entitlements Controlling MTE
| Entitlement | Effect |
|---|---|
com.apple.security.hardened-process |
Enable MTE (platform binaries only) |
com.apple.security.hardened-process.checked-allocations |
Enable MTE explicitly |
...checked-allocations.soft-mode |
“Soft” mode = non-fatal faults. Ignored for platform binaries in lockdown. Forced for third-party (until iOS 26.4) |
...checked-allocations.{enable,disable}-pure-data |
Tag data-only allocations too (opt-out since iOS 26.4) |
Task Properties
// Khi activating MTE, XNU:
task->security_config.sec = true;
task->task_sec_policy = MTE_CONFIGURATION;
// Inject boot arg: has_sec_transition=1
// Kiểm tra MTE status:
task_has_sec_*() // Family of check functions
VM Layer Integration (Userland)
MTE-capable task → allowed to use VM_FLAGS_MTE khi request memory
→ MTE enforced ở mọi level trong XNU VM structures
→ Associated PTE indicates page can be tagged
→ MTE-capable memory allocator dùng tagged pages
Limitations:
- No CoW (Copy-on-Write) for tagged memory
- Inheritance / OOL mach message → force copy, tags stripped
Impact cho exploitation:
- OOL mach message spray — tags stripped khi copy → spray data untagged
- CoW-based PUAF techniques (smith) — CoW disabled cho tagged memory
- Cross-process memory sharing — tags not inherited
VM Layer Integration (Kernel)
| Layer | API | Role |
|---|---|---|
| VM | vm_page_grab*() |
Physical page allocation, can provide tagged page (VM_PAGE_GRAB_MTE) |
| VM | vm_page_alloc_list() |
Batch allocation, can provide tagged page (KMA_TAG) |
| kmem | kmem_alloc*() |
Huge wired allocations (page-granular), can provide tagged page (KMA_TAG) |
VM_PAGE_GRAB_MTE / KMA_TAG chỉ dùng qua exclaves_memory_alloc, kalloc_large, và Zalloc APIs.
Kernel Allocators — Zalloc MTE Integration
XNU Heap Architecture Với MTE
| Layer | API | Role |
|---|---|---|
| zalloc | zalloc(), zalloc_flags() |
Fixed-sized zones (SLAB, up to 32KB), enforcing MTE policy |
| kalloc / kalloc_type | kalloc_ext(), kalloc_type(T) |
Generic subsystem allocations, type segregation |
| IOKit | IOMalloc() |
Wraps kheap_alloc → kalloc_ext |
Existing Zalloc Defenses (Pre-MTE)
| Defense | Targets |
|---|---|
| External bitmap | No inline metadata to corrupt, double-free detection |
| Heap separation (DATA / PTR / SHARED) | Cross-type exploitation |
| VA sequestering | Cross-zone attacks (VA pinned to zone forever) |
| Sad Feng Shui / Per-CPU anti-LIFO magazines | Predictable heap feng shui |
| zone_require() | Validates zone ownership at runtime |
| Guard pages (random ~25%) | Linear overflows between zone chunks |
| Type segregation (kalloc_type) | Type confusion via heap spraying |
MTE Tagging In Zalloc
Tagging activation:
z_tag bit trong zone's zone_security_flags_t (defaults to 1, except RO / DATA)
→ Forces zone to init/expand via KMA_TAG and tag blocks
Since iOS 26.4:
z_tag replaced by runtime zone_submap_has_tagging_enabled
→ Still avoid tagging for RO submap
→ CAN enable tagging for DATA submap
→ KHEAP_ID_DATA_BUFFERS split into:
KHEAP_ID_DATA_PRIVATE (tagged)
KHEAP_ID_DATA_SHARED (not tagged)
Tag-on-Free Policy
Lifecycle:
1. Zone init/expansion (zcram_memtag_init):
→ New page grabbed → zcram_memtag_init() tags ALL blocks
→ Even/odd position → different tag spaces
→ Even blocks: tag space {2, 4, 6, 8, A, C, E}
→ Odd blocks: tag space {1, 3, 5, 7, 9, B, D}
→ Adjacent blocks ALWAYS have different parity tags
2. Allocation (zalloc):
→ Block already tagged from init → vm_memtag_load_tag()
→ Returns pointer WITH embedded tag
→ Ready to use immediately
3. Free (zfree):
→ Block position determined (odd/even)
→ RETAG with new random tag from OPPOSITE parity
→ Excludes current tag → guarantee different tag
→ Old pointer's tag will NOT match → UAF detected!
XNU Source Code
// zcram_memtag_init — tag blocks when zone expands
static inline void zcram_memtag_init(zone_t zone,
vm_offset_t base, uint32_t start, uint32_t end)
{
if (!zone_submap_has_tagging_enabled(zone_security_config(zone))) { return; }
vm_size_t elem_size = zone_elem_outer_size(zone);
vm_size_t oob_offs = zone_elem_outer_offs(zone);
for (uint32_t i = start; i < end; i++) {
vm_offset_t addr = base + oob_offs + i * elem_size;
#if HAS_MTE
addr = (vm_offset_t)mte_generate_and_store_tag((caddr_t)addr,
elem_size, zone_mte_exclusion_mask((zone->z_chunk_elems - i) & 1));
#endif
}
}
Tại Sao MTE Khiến Exploitation Cực Kỳ Khó
UAF Detection
1. c1 = zalloc(zone) → c1 tagged with tag T1
2. zfree(c1) → memory RETAGGED with T2 (≠ T1)
3. *c1 → pointer tag = T1, memory tag = T2
→ MISMATCH → FAULT
→ UAF DETECTED!
Nếu c1 freed và reallocated cho c2:
4. c2 = zalloc(zone) → c2 gets NEW tag T3 (≠ T1, ≠ T2)
5. *c1 → pointer tag T1 ≠ memory tag T3
→ FAULT → Object confusion DETECTED!
Linear Overflow Detection
Adjacent blocks có different parity tags:
Block 0 (even): tag from {2, 4, 6, 8, A, C, E}
Block 1 (odd): tag from {1, 3, 5, 7, 9, B, D}
Overflow from block 0 → block 1:
→ Pointer tag (even) ≠ memory tag (odd)
→ ALWAYS caught (different parity = guaranteed mismatch)
OOB to Same-Parity Block
OOB vào block cùng parity (skip 1 block):
→ Tag space overlap → 1/7 chance of matching
→ NOT always caught, but probabilistic detection
Impact Cho Exploitation
Pre-MTE vs Post-MTE Attack Strategies
Pre-MTE (zalloc hardening + kalloc_type already made it hard):
✗ Layout difficult to predict (anti-LIFO, random magazines)
✗ Overflow/OOB might face guard pages
✗ Type confusion almost impossible (kalloc_type)
✗ Double free detected (external bitmap)
✓ BUT: UAF → same-type Object Confusion still possible
(mach ports, memory descriptors, etc.)
Post-MTE:
✗ UAF → Object Confusion: TAGGED, different tag → FAULT
✗ Overflow: adjacent = different parity → FAULT
✗ Linear overflow: always caught
→ MOST heap exploitation techniques DEAD
What Attackers Can Still Do
MTE buộc attackers phải thay đổi strategy:
| Strategy | Viability |
|---|---|
| Attack untagged allocations (DATA-only, huge allocations) | iOS 26.4 closed the DATA gap |
| Intra-object primitives (corrupt fields WITHIN same object, same tag) | Possible — then potentially leak tags |
| Physical-level operations (DarkSword-style VFS race → physrw) | Bypasses MTE entirely (physical layer has no tags) |
| Hunt for other bug classes (logic bugs, parser disagreements) | Not affected by MTE |
| Tag leaking via side channels | Apple designed SoC to be resistant, but active research area |
Userland Allocators
- libmalloc: MTE support integrated
- libpas (WebKit’s allocator): now supporting MTE, but temporarily forced to soft-mode
- Soft-mode = non-fatal faults (log but don’t crash) — easier transition, less protection
- Platform binaries in lockdown mode: soft-mode ignored (hard faults enforced)
- Third-party apps: forced soft-mode until iOS 26.4
MTE Trong Mitigation Timeline
iOS 6: KASLR
iOS 9: KPP (software)
iOS 10: KTRR (hardware kernel text protection)
PAN (Privileged Access Never)
iOS 12: PAC (Pointer Authentication)
PPL (Page Protection Layer)
APRR/SPRR
iOS 13: zone_require
iOS 15: kalloc_type (type-isolated zones)
CTRR (Configurable Text Readonly)
iOS 17: SPTM + TXM (EL2 separation)
iOS 18: Exclaves
iOS 26: MIE/MTE (Memory Integrity Enforcement) ← NEW: hardware memory tagging
Tag Confidentiality (PRNG reseed, SPTM-protected tag storage)
Combined: SPTM + TXM + Exclaves + MTE = most hardened OS kernel in existence
Tài Nguyên
- “Navigating the MTE Landscape: iOS Memory Protection Deep Dive” — Atlan Pinabel & Patrick Ventuzelo, FuzzingLabs, OffensiveCon 2026
- ARM MTE Specification (ARMv8.5-MemTag)
- Apple — Towards the Next Generation of XNU Memory Safety: kalloc_type
- XNU source:
osfmk/kern/zalloc.c(MTE integration),osfmk/arm64/pmap.c(tag storage) - Research on MTE bypasses: TikTag, StickyTag (speculative side channels)