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 size'ı page-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_reapiç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.