Skip to content

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.

References