Skip to content

Disable SMEP via CR4 ROP

Bir mov cr4, rdi gadget'ı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.

References