set_memory_x page-table attack¶
set_memory_x()'i kötüye kullan (ya da NX bit'ini temizlemek için page-table entry'lerini doğrudan corrupt et); böylece writable bir kernelpage'i executable hale gelir ve enjekte edilen shellcode kernel mode'da çalışır.
Mechanism¶
set_memory_*() API'si, bir kernel virtual address aralığının attribute'larını onu map'leyen page-table entry'lerini düzenleyerek değiştirir. Kernel header'ı attribute'ların "Cacheability, Executability, Read/Write, Presence, Encryption" içerdiğini belirtir. set_memory_x(addr, numpages), numpages'i kapsayan PTE'lerdeki NX bit'ini (x86'da _PAGE_NX; arm64'te UXN/PXN) temizler ve aralığı executable yapar; set_memory_nx() tersini yapar.
Note
Executability, en temelde tek bir page-table bit'idir. (a) içeriğini de kontrol ettiği bir kernel bölgesinde set_memory_x()'i çağırabilen ya da (b) NX'i temizlemek için ilgili PTE'yi doğrudan corrupt edebilen bir attacker, writable bir kernel page'inde attacker'ın yazdığı byte'ları executable yapar. Bu, o page için W^X / NX'i yener ve saf bir ROP payload'ına ihtiyaç duymadan kernel shellcode'unu indirecek bir yer verir.
Walkthrough¶
İlgili kernel yüzeyi (imzalar ve semantik):
/* include/linux/set_memory.h (generic no-op stubs when CONFIG_ARCH_HAS_SET_MEMORY unset) */
static inline int __must_check set_memory_x(unsigned long addr, int numpages){ return 0; }
static inline int __must_check set_memory_nx(unsigned long addr, int numpages){ return 0; }
/* arch/x86 supplies the real implementation that walks/splits PTEs */
Bir write veya call primitive var olduğunda kavramsal attack path'i:
- Shellcode'u writable bir kernel
page'ine yerleştir (ör. bir BPF map, spray'lenmiş bir slab object ya da direct map). - Ya hijack edilmiş bir function pointer/ROP aracılığıyla
set_memory_x(page, 1)çağır, ya da bir page-table write primitive kullanarak opage'in PTE'sindeki_PAGE_NXbit'ini bul ve temizle. - Control flow'u artık executable olan
page'e yönlendir; shellcode ring 0'da çalışır (ör.commit_creds(prepare_kernel_cred(0))).
Beklenen sonuç: W ve NX olan bir page, W+X olur ve içeriğinin yürütülmesi supervisor mode'da başarılı olur.
Mitigation¶
Strict kernel W^X (CONFIG_STRICT_KERNEL_RWX), set_memory_* path'lerini ve page table'ların kendisini mümkün olduğunda read-only yapmak, SLAT (EPT/NPT) aracılığıyla hypervisor-enforced W^X ve corrupt edilmiş bir pointer üzerinden executable page'e ulaşmayı durduran CFI, hepsi bunu köreltir. Bir PTE'nin NX bit'ine ulaşabilen herhangi bir data-only write'ı RIP'e eşdeğer say.