Disable SMEP via CR4 ROP¶
Bir
mov cr4, rdigadget'ına ROP yaparak CR4.SMEP (bit 20) / SMAP (bit 21)'i temizle, böylece bir ret2usr payload'ını yeniden etkinleştir — modern CR4 pinning ile etkisizleştirilir.
Mechanism¶
Note
CR4.SMEP (bit 20, 0x100000), ring-0 bir user-accessible page'i execute ettiğinde
CPU'nun fault üretmesini sağlar; CR4.SMAP (bit 21, 0x200000), ring-0'ın user page'lere
data erişiminde fault üretir. Bir kernel exploit'i control flow'u hijack eder ve RDI'ya
bir attacker değeri yükleyip mov cr4, rdi çalıştıran bir gadget'a ROP yapar
(native_write_cr4() içinde). Bit 20/21'i temizlenmiş bir CR4 değeri seçmek SMEP/SMAP'i
devre dışı bırakır; ardından chain userspace'e ret edebilir — kanonik
ret2usr escalation'ı.
SMEP'in enforce ettiği invariant (kernel asla user page'leri execute etmez), CR4'e yapılan tek bir write ile kırılır; CR4 pinning bunu geri getirir.
Walkthrough¶
CR4 bit sabitleri: X86_CR4_SMEP = bit 20 (0x100000), X86_CR4_SMAP = bit 21
(0x200000).
Pinning öncesi chain:
pop rdi ; ret -> 0x6f0 ; CR4 with SMEP/SMAP cleared
mov cr4, rdi ; ret (native_write_cr4)
ret -> userspace escalation stub (commit_creds(...))
CR4 pinning (Linux 5.1+, Kees Cook)
Hassas bit'ler read-only-after-init olarak saklanır ve her write'tan sonra yeniden assert edilir:
/* mask = X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_UMIP, in cr4_pinned_bits */
if (unlikely((val & cr4_pinned_bits) != cr4_pinned_bits)) {
bits_missing = ~val & cr4_pinned_bits;
val |= bits_missing;
goto set_register; /* re-assert the bits */
}
WARN_ONCE(bits_missing, "CR4 bits went missing: %lx!?\n", bits_missing);
Pinning yapılmış bir kernel'de SMEP-temizleyen write bir no-op'a dönüşür ve dmesg'te
WARN_ONCE'ı tetikler.
Detection¶
Pinning yapılmış bir kernel, WARN_ONCE aracılığıyla CR4 bits went missing log'lar (bu yüzden
dmesg_restrict'in attacker'lar için bir önemi vardır).
Mitigation¶
CR4 pinning (SMEP/SMAP/UMIP'i kapsar, sonradan +FSGSBASE) basit "native_write_cr4 çağır"
yolunu etkisizleştirir. Genel bir ROP/CFI koruması değildir: bypass'lar CR4'e dokunmadan
kernel içinde tüm prepare_kernel_cred/commit_creds dizisini ROP'lar ya da pinning'lenmiş
helper olmayan ham bir mov-to-CR4 gadget'ı kullanır. Bkz.
SMEP ve
SMAP.