Virtual memory subsystem quαΊ£n lΓ½ translation giα»―a virtual addresses (mΓ  code dΓΉng) vΓ  physical addresses (RAM thαΊ­t). Page tables lΓ  data structure chα»©a mapping nΓ y. Bugs trong VM subsystem dαΊ«n Δ‘αΊΏn physical read/write β€” primitive mαΊ‘nh nhαΊ₯t.


TαΊ‘i Sao CαΊ§n Hiểu VM

  • Physical UAF (PUAF) exploits khai thΓ‘c bugs trong VM subsystem
  • Page table manipulation lΓ  cΓ‘ch bypass PPL/SPTM
  • physrw (physical read/write) Δ‘αΊ‘t được qua dangling page table entries
  • KASLR dα»±a vΓ o VM β€” hiểu VM = hiểu cΓ‘ch leak kernel base
  • pmap code lΓ  target cho nhiều kernel bugs

ARM64 Address Translation

Translation Table Walk

Virtual Address (48-bit):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ L1 idx β”‚ L2 idx β”‚ L3 idx β”‚ Page   β”‚ Page offset  β”‚
β”‚ [47:39]β”‚ [38:30]β”‚ [29:25]β”‚ [24:14]β”‚ [13:0]       β”‚
β”‚ 9 bits β”‚ 9 bits β”‚ 5 bits β”‚ 11 bitsβ”‚ 14 bits      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
   (iOS dΓΉng 16KB pages β†’ offset = 14 bits)

Translation:
  TTBR1_EL1 (kernel) hoαΊ·c TTBR0_EL1 (user)
       β”‚
       β–Ό
  L1 Table ──[L1 idx]──→ L1 Entry β†’ L2 Table base
                              β”‚
                              β–Ό
                         L2 Table ──[L2 idx]──→ L2 Entry β†’ L3 Table base
                                                    β”‚
                                                    β–Ό
                                               L3 Table ──[L3 idx]──→ L3 Entry
                                                                         β”‚
                                                                         β–Ό
                                                                   Physical Page
                                                                    + offset
                                                                         β”‚
                                                                         β–Ό
                                                                   Physical Address

Page Table Entry (PTE) Format

L3 Page Table Entry (arm64, 16KB granule):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 63    59β”‚58  55β”‚54  52β”‚51          14β”‚13  12β”‚11  10β”‚9  8β”‚...β”‚
β”‚ ignored β”‚ SW   β”‚ res  β”‚ Output Addr  β”‚ res  β”‚  AP  β”‚ SH β”‚...β”‚
β”‚ by HW   β”‚ use  β”‚      β”‚ (phys page)  β”‚      β”‚      β”‚    β”‚   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ ...β”‚7  6β”‚5β”‚4  2β”‚1β”‚0β”‚
β”‚    β”‚ resβ”‚ β”‚MAIRβ”‚ β”‚Vβ”‚
β”‚    β”‚    β”‚ β”‚idx β”‚ β”‚aβ”‚
β”‚    β”‚    β”‚ β”‚    β”‚ β”‚lβ”‚
β”‚    β”‚    β”‚ β”‚    β”‚ β”‚iβ”‚
β”‚    β”‚    β”‚ β”‚    β”‚ β”‚dβ”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key fields:
  Bit 0 (Valid)     : 1 = entry valid, 0 = fault on access
  Bits 4:2 (AttrIdx): Memory attribute index (MAIR register)
  Bits 7:6 (AP)     : Access Permission
                       00 = EL1 R/W, EL0 no access
                       01 = EL1 R/W, EL0 R/W
                       10 = EL1 R/O, EL0 no access
                       11 = EL1 R/O, EL0 R/O
  Bits 9:8 (SH)     : Shareability (Inner/Outer/None)
  Bit 10 (AF)       : Access Flag (set by HW on first access)
  Bit 54 (XN)       : Execute Never (EL1)
  Bit 53 (PXN)      : Privileged Execute Never
  Bits 51:14        : Physical address of page (shifted)

Address Permissions Summary

AP[7:6] EL1 (kernel) EL0 (user)
00 Read/Write No access
01 Read/Write Read/Write
10 Read-only No access
11 Read-only Read-only

XNU Virtual Memory Subsystem

VM Map

// vm_map = address space representation
struct vm_map {
    struct vm_map_header    hdr;        // Sorted list of vm_map_entry
    pmap_t                  pmap;       // Machine-dependent page tables
    vm_map_size_t           size;       // Virtual size
    // ...
};

// vm_map_entry = one contiguous mapping
struct vm_map_entry {
    struct vm_map_entry *prev, *next;   // Doubly-linked list
    vm_map_offset_t     vme_start;      // Start virtual address
    vm_map_offset_t     vme_end;        // End virtual address
    vm_prot_t           protection;     // Current protection
    vm_prot_t           max_protection; // Maximum allowed protection
    // ...
    union {
        vm_object_t     vme_object;     // Backing object (file, anonymous)
    };
};

Pmap (Physical Map)

// pmap = machine-dependent page table management
struct pmap {
    tt_entry_t          *tte;           // Top-level page table pointer
    uint64_t            asid;           // Address Space ID (for TLB)
    // ...
};

Key pmap functions:

// Create mapping: virtual β†’ physical
pmap_enter_options(pmap, va, pa, prot, fault_type, flags, options);

// Remove mapping
pmap_remove(pmap, start, end);

// Change protection
pmap_protect(pmap, start, end, prot);

// Query mapping
pmap_find_phys(pmap, va);  // Returns physical page number

TLB (Translation Lookaside Buffer)

TLB = cache cho page table entries. CPU khΓ΄ng walk page tables mα»—i memory access β€” nΓ³ check TLB trΖ°α»›c.

CPU needs virtual β†’ physical translation
  β”œβ”€β†’ Check TLB (fast path)
  β”‚     β”œβ”€β†’ TLB hit: use cached translation
  β”‚     └─→ TLB miss: walk page tables (slow path)
  β”‚           └─→ Insert result into TLB
  └─→ Access physical memory

TLB invalidation (TLBI instruction) cαΊ§n thiαΊΏt khi:

  • Thay Δ‘α»•i page table entries
  • Context switch (ASID change)

Bug pattern: Kernel thay Δ‘α»•i PTE nhΖ°ng quΓͺn invalidate TLB β†’ stale translation vαΊ«n dΓΉng β†’ security violation.


Physical Use-After-Free (PUAF)

Concept

1. Process A maps virtual address VA β†’ physical page P
2. Bug: kernel frees physical page P nhΖ°ng KHΓ”NG remove mapping tα»« process A's page tables
3. Kernel reallocates physical page P cho purpose khΓ‘c (kernel object, page table, ...)
4. Process A vαΊ«n đọc/ghi P thΓ΄ng qua VA β†’ đọc/ghi kernel data!

PUAF β†’ physrw Escalation

Nếu page P trở thành Level 3 page table:
  β”œβ”€β†’ Process A ghi vΓ o P = modify page table entries
  β”œβ”€β†’ TαΊ‘o PTE mα»›i trỏ Δ‘αΊΏn BαΊ€T Kα»² physical address
  β”œβ”€β†’ Map toΓ n bα»™ DRAM vΓ o address space
  └─→ Full physical read/write!

Nếu page P trở thành kernel object:
  β”œβ”€β†’ Process A ghi vΓ o P = corrupt kernel object
  └─→ Escalate to kread/kwrite

Defenses (iOS 17+ SPTM)

SPTM ensures:
  - Physical pages track their "type" (user, kernel, page table, ...)
  - User pages CANNOT be reallocated as kernel pages until next boot
  - Page table modifications MUST go through SPTM (EL2)
  β†’ PUAF from user β†’ kernel is blocked
  β†’ PUAF user β†’ user still possible (less useful)

Page Lifecycle

Free page pool
  β”‚
  β”œβ”€ vm_page_grab() β†’ Allocate physical page
  β”‚   └─ pmap_enter() β†’ Map into address space
  β”‚
  β”œβ”€ pmap_remove() β†’ Remove mapping
  β”‚   └─ vm_page_free() β†’ Return to free pool
  β”‚
  └─ PUAF bug: vm_page_free() WITHOUT pmap_remove()
       β†’ Page returned to free pool but still mapped!

Kernel Memory Regions

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Kernel Virtual Address Space           β”‚
β”‚                                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”               β”‚
β”‚  β”‚ Kernelcache         β”‚ Fixed mapping  β”‚
β”‚  β”‚ (__TEXT, __DATA)     β”‚ KASLR slide   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”               β”‚
β”‚  β”‚ Zone maps           β”‚ Dynamic       β”‚
β”‚  β”‚ (kalloc, ipc, ...)  β”‚               β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”               β”‚
β”‚  β”‚ Kernel map          β”‚ General       β”‚
β”‚  β”‚ (large allocations) β”‚ purpose       β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”               β”‚
β”‚  β”‚ MMIO regions        β”‚ Device        β”‚
β”‚  β”‚ (hardware registers)β”‚ mappings      β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

TΓ i NguyΓͺn


BΓ i TαΊ­p

  1. Manual page table walk: Cho virtual address, TTBR value, vΓ  page table dumps β€” compute physical address by hand
  2. Read pmap.c: Trace pmap_enter_options() β€” hiểu mα»—i parameter lΓ m gΓ¬
  3. Analyze PUAF exploit: Đọc kfd source code, trace PUAF primitive (smith/landa/physpuppet)
  4. Draw memory map: Cho 1 running process, dΓΉng vmmap (macOS) vαΊ½ full address space layout
  5. Compute PTE values: Cho physical address + desired permissions, construct PTE value by hand