commit_creds(prepare_kernel_cred(0))¶
Klasik credential-swap finalizer'ı: kernel fonksiyonlarını çağırabildiğin anda mevcut task'a taze bir root credential kur.
Mechanism¶
struct cred *prepare_kernel_cred(struct task_struct *daemon) taze bir credential yapısı allocate eder. Tarihsel olarak NULL/0 geçmek, uid/gid 0, supplementary group olmayan ve tam capability'lere sahip default bir credential üretirdi (init_cred'den türetilir). int commit_creds(struct cred *new) ise bu credential'ı mevcut task'a kurar, hem task->real_cred'i hem de task->cred'i günceller.
Note
commit_creds(prepare_kernel_cred(0)), geçerli, reference-counted yapılar kullanarak
çağıran task'ı atomik olarak tamamen root yapar — herhangi bir heap adresinin bilinmesi
gerekmez. Kernel-mode code execution'a (ROP) ya da kernel fonksiyonlarını çağırmanın bir
yoluna (örn. bir eBPF helper-call confusion) sahip olduğunda kullanılan standart
finalizer'dır. Doğrudan bir cred-field overwrite'a kıyasla, mevcut olanı yerinde
mutate etmek yerine tutarlı, RCU-safe bir credential üretir.
Walkthrough¶
Her iki sembolü /proc/kallsyms'ten (ya da bir KASLR base + offset'ten) resolve et. Shellcode formu:
xor rdi, rdi ; arg = 0
movabs rax, prepare_kernel_cred
call rax
mov rdi, rax ; new cred = return value
movabs rax, commit_creds
call rax
; then iretq / KPTI trampoline back to userland and spawn a shell
Pure-ROP bir chain'de bu iki aşamaya bölünür: pop rdi; ret ile rdi=0 yap, prepare_kernel_cred'i çağır, rax'ı sakla, sonra kaydedilen cred'i pop rdi ile yükle ve commit_creds'i çağır. Userland'e döndükten sonra getuid() 0 döner ve system("/bin/sh") bir root shell verir.
Kernel-version footgun (Linux 6.2+)
397d425dc26d commit'i "cred: Do not default to init_cred in prepare_kernel_cred()"
(Kees Cook, Linux 6.2'de merge edildi) if (WARN_ON_ONCE(!daemon)) return NULL; ekledi.
6.2 sonrası kernel'lerde prepare_kernel_cred(NULL) NULL döner, dolayısıyla
commit_creds(NULL) artık seni root yapmaz ve oops verebilir. Exploit-dev karşılığı,
0 yerine &init_task (KASLR'a göreli bir sembol) geçmektir:
prepare_kernel_cred(&init_task) hâlâ root cred türetir. Bu anti-exploitation
hardening, attacker'ları uygun ayrıcalığa sahip bir task_struct pointer'ı vermeye
zorlar.
Mitigation¶
prepare_kernel_cred(NULL) → NULL değişikliği (6.2+), literal prepare_kernel_cred(0) formunu kırar. Control-flow integrity (CFI/FineIBT) ve CONFIG_RANDSTRUCT, bu çağrılara ulaşan ROP path'inin çıtasını yükseltir ve attacker'ları modprobe_path overwrite gibi data-only finalizer'lara yöneltir.