ret2usr¶
Bir kernel code pointer'ını overwrite ederek, ring 0'da çalışırken control flow'u attacker-controlled bir userspace virtual address'inde duran code ya da data'ya atlatmak.
Mechanism¶
Tarihsel olarak kernel ve mevcut user process tek bir address space'i paylaşır: kernel page'leri ve user page'leri ikisi de aynı page table'lar tarafından (farklı protection bit'leriyle) map'lenir. Dolayısıyla CPU supervisor mode'dayken bir kernel virtual address ve bir user virtual address aynı anda erişilebilir durumdadır.
Note
ret2usr, kernel-controlled bir pointer'ı — kaydedilmiş bir return address, bir function pointer ya da bir dispatch-table entry — corrupt eder ve onu attacker'ın önceden doldurduğu bir userland address'ine yönlendirir. User mapping ring 0'da canlı olduğu için, kernel attacker data'sını architecturally fetch edip kernel privilege'larıyla çalıştırır. Klasik payload, current task'ı root yapmak için commit_creds(prepare_kernel_cred(0)) çağıran ufak bir userland stub'tır ve sonra temiz bir şekilde userspace'e geri döner.
Bu, mümkün olan en ucuz escalation primitive'idir: attacker tüm payload'u zahmetsizce kontrol eder (sadece normal bir userspace buffer/function'dır), kernel base'i leak etmeye ya da bir ROP chain kurmaya gerek kalmadan.
Walkthrough¶
Bir kernel pointer overwrite edilebilir hale geldiğinde minimal bir ret2usr escalation:
// 1. Userland payload that the kernel will be tricked into running.
void __attribute__((regparm(0))) payload(void) {
commit_creds(prepare_kernel_cred(0)); // resolve addrs first (e.g. /proc/kallsyms)
}
// 2. Userland frame for clean return to ring 3 (iretq target).
struct trap_frame { void *rip; uint64_t cs, rflags, rsp, ss; } tf;
void save_state(void){ asm volatile("mov %%cs,%0; mov %%ss,%1; mov %%rsp,%2; pushfq; pop %3;"
: "=m"(tf.cs),"=m"(tf.ss),"=m"(tf.rsp),"=m"(tf.rflags)); }
// 3. Trigger the bug so a kernel function pointer == &payload, then enter the kernel path.
Beklenen sonuç: corrupt edilmiş handler ring 0'da payload'u çalıştırır; sonrasında getuid() 0 döndürür.
Mitigation¶
Hardware ve software defense'leri "kernel user address çalıştırır" varsayımını kırar:
- SMEP (Supervisor Mode Execution Prevention, x86'da bir CR4 bit'i) kernel bir user page'i execute ederse fault verir — "jump to userspace shellcode"u öldürür.
- SMAP (CR4) kernel bir user page'i read/write ederse fault verir — user page'leri sahte kernel data'sı olarak kullanmayı öldürür.
- PXN (ARM, Privileged eXecute Never) SMEP'in karşılığıdır.
- KPTI user mode'dayken çoğu kernel page'ini unmap eder (ayrı page table'lar), ve PaX/grsecurity'nin KERNEXEC/UDEREF ve kGuard'ı software CFI-tarzı check'ler ekler.
Warning
SMEP genellikle, userspace'e pivot etmeden önce CR4'teki SMEP bit'ini flip eden (native_write_cr4) kernel ROP ile bypass edilir, ya da ret2dir ile tamamen atlatılır; bu da attacker-controlled user page'lerini kernel physmap'ine alias'layarak hijack edilmiş pointer'ın bir kernel address'ine resolve olmasını sağlar.