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/LDG qua 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_allockalloc_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