Skip to content

PhysPuppet (CVE-2023-23536)

mach_memory_object_memory_entry_64()'teki page-aligned olmayan bir named-entry size'ı, VM map'i page table'larla desenkronize eder ve freed physical page'lerde dangling read/write PTE'ler bırakır — Apple platformlarında bir physical use-after-free (PUAF).

Mechanism

PhysPuppet, felix-pb'nin iOS/macOS için kfd ("kernel file descriptor") PUAF exploit'lerinden biridir. Bug Mach VM'de yaşar: mach_memory_object_memory_entry_64(), userspace'in sizepage-aligned olmayan bir named entry oluşturmasına izin verir.

Note

Kernel'in koruması gereken invariant şu: bir vm_map_entry tarafından tanımlanan mapping kümesi ile o range için pmap'e kurulan geçerli PTE kümesi uyuşmalıdır. Canlı bir VM entry'sinin kapsadığı her page erişilebilirdir; herhangi bir canlı entry'nin dışındaki her page'in PTE'leri, physical page free edilmeden önce sökülmelidir. PhysPuppet bu uyuşmayı kırar: named entry, aligned olmayan bir size (2P + 1, burada P page size'ıdır) ile oluşturulur, dolayısıyla map'lendiğinde vm_map_enter() range'i bir yöne yuvarlarken per-page fault/teardown mantığı başka bir yöne yuvarlar. pmap_remove_options_internal() tarafından kullanılan end address'in aligned olmayan "page offset"i kaydırılıp atılır, dolayısıyla unmap'te yalnızca ilk PTE temizlenir ve ikinci page'in PTE'si kurulu bırakılır. Named entry deallocate edildiğinde, vm_object_reap() alttaki physical page'leri pmap_disconnect() olmadan free eder ve artık-free bir physical page'i gösteren writable dangling bir PTE bırakır.

Sonuç bir PUAF'tir: PTE'si hâlâ read+write veren ama physical page'i free list'e dönmüş ve arbitrary kernel object'leri tutmak üzere yeniden allocate edilebilen bir virtual address.

Walkthrough

Exploit (kfd'deki physpuppet_run()) altı adımda ilerler. Kavramsal olarak:

// 1. Create a named entry vmne1 with an UNALIGNED size = 2*P + 1
mach_memory_object_memory_entry_64(mach_host_self(),
        /*internal=*/TRUE, /*size=*/ (2*PAGE_SIZE) + 1,
        VM_PROT_READ | VM_PROT_WRITE, MEMORY_OBJECT_NULL, &vmne1);

// 2. Map it -> vm_map_enter() sees unaligned size 1*P + 1
vm_map(..., vmne1, ...);

// 3. Fault in two pages vmp1, vmp2 backed by the same vm_object vmo1
//    (touch both pages so PTEs are installed)

// 4. Unmap. pmap_remove_options_internal() clears only the FIRST PTE;
//    the end address' unaligned offset is shifted off, so vmp2's PTE survives.

// 5. Deallocate the named entry. vm_object_reap() frees vmp1 and vmp2
//    WITHOUT pmap_disconnect() -> dangling R/W PTE on vmp2 (now free).

// 6. Re-map a covering vm_map_entry so process exit does not panic.

Step 5'ten sonra process bir PUAF primitive tutar: freed bir physical page'i okuyup yazan bir user VA.

PUAF'i kernel R/W'ye çevirmek

kfd, dangling page'leri kernel object'leriyle reclaim eder ve onları dangling PTE üzerinden tarar:

  • krkw_helper_grab_free_pages() freed page'leri pin'ler, ardından bir spray (örn. socket'ler / kqworkloop / fileproc) bir hedef object'i bir PUAF page'ine düşürür.
  • Exploit tanınabilir bir object arar, içindeki non-PAC'd bir pointer'ı corrupt eder ve corruption üzerinden okumak/yazmak için bir syscall kullanır (kread/kwrite), arbitrary kernel R/W'yi bootstrap eder.

Detection

  • mach_memory_object_memory_entry_64() / named-entry oluşturmayı, page-multiple olmayan size'lar için denetle.
  • Etkilenen build'lerde pmap_remove/vm_object_reap içinde beklenmedik kernel panic'leri exploitation girişimlerine işaret edebilir.

Mitigation

  • Apple tarafından iOS 16.3 / macOS 13.2'de (CVE-2023-23536) named-entry size'ı doğrulanıp/align'lanarak VM map ile pmap senkron tutulacak şekilde düzeltildi.
  • Genel PUAF sınıfı zone_require() ("data-PAC'a benzer etki" ile forged kernel pointer'ları engelleyen) ve daha yeni Apple silicon'da PPL/SPTM physical-page korumalarıyla sınırlanır.

References