CVE-2023-4211: Use-after-Free in ARM Mali GPU Driver (exploited in the wild)¶
Mali kernel driver'ının per-context
mm_structtracking pointer'ı üzerindeki bir lifecycle race, free edilmiş birmm_struct'ın free sonrası referans edilmesine izin verir; unprivileged bir process, free edilmiş memory'ye ulaşmak için hatalı GPU memory bookkeeping'i tetikler. In-the-wild exploit edildi ve CISA KEV'de listelendi.
Mechanism¶
Invariant: kctx->process_mm, kendisinin her dereference'inden daha uzun yaşamalı
Mali driver'ı, kernel'in RSS accounting'i GPU-backed page'leri yansıtsın
diye GPU page kullanımını sahip process'in memory descriptor'ına
(mm_struct) geri yükler. Her Mali context'i (kctx), o descriptor'a bir
pointer'ı kctx->process_mm'de cache'ler. Doğruluk invariant'ı basit:
kctx->process_mm'i okuyup sonra üzerinde accounting yapan herhangi bir kod,
operasyon süresince mm_struct'ın hâlâ canlı (refcount'lu veya başka şekilde
pin'li) olduğunu garanti etmeli.
kbasep_os_process_page_usage_drain() bunu ihlal eder. Dizisi şu:
1. take the lock, read the old mm pointer into a local
2. set kctx->process_mm = NULL, drop the lock
3. synchronize_rcu() <-- long preemptible window
4. kbasep_add_mm_counter(mm, ...) <-- uses the *local* mm copy
- ve 4. adımlar arasında driver, hiçbir reference count onu pin'lemezken
mm_struct'a korumasız bir local reference tutar. Driver ayrıca context başına bir tracking VMA varsayar; o VMA'yımunmap()ile bölmek varsayımı kırar vefork()ile birleşince bir process'inkctx'inin farklı, artık çıkmakta olan bir child'ınmm_struct'ını tutmasına yol açar. O child'ınmm_struct'ı free edilip reallocate edildiğinde 4. adım accounting delta'larını yeniden kullanılmış bir object'e yazar -- yüksek değerli, sık allocate edilen bir kernel structure'ı üzerinde klasik bir use-after-free.
mm_struct genel bir kmalloc cache'inde yaşadığı için bu, sıradan SLUB
exploitation'ın giriş noktasıdır: free edilmiş slot'u kontrol edilebilir bir
object'le reclaim et (slab-grooming,
cross-cache-attack), sonra privilege escalation için
onu corrupt et. Pattern, mali-gpu-iommu-race
gibi diğer Mali GPU use-after-free
LPE'lerinin yakın akrabasıdır. Daha genel olarak aynı reclaim-then-corrupt
şablonu, ismi tarihsel bir "GPU" alias'ı olsa da gerçekte bir posix-cpu-timers
race'i olan android-gpu-use-after-free-lpe
dahil, subsystem'den bağımsız tüm kernel UAF LPE'lerini birleştirir.
Walkthrough¶
Bug tamamen standart process/memory syscall'ları artı bir Mali context üzerinden sürülür; özel privilege gerekmez.
/* 1. Open the Mali device and create a context. */
int mali = open("/dev/mali0", O_RDWR);
/* KBASE_IOCTL_VERSION_CHECK + KBASE_IOCTL_SET_FLAGS to init the context ... */
/* 2. Map the GPU tracking region, then split it so the single-VMA-per-context
* assumption is broken. munmap() of a middle page splits one VMA into two. */
void *track = mmap(NULL, 3 * PAGE_SIZE, PROT_READ|PROT_WRITE,
MAP_SHARED, mali, BASE_MEM_MAP_TRACKING_HANDLE);
munmap((char *)track + PAGE_SIZE, PAGE_SIZE); /* split the tracking VMA */
Cross-process confusion fork() ile kurulur: child, Mali context'i
parent'ın drain path'i child'ın mm_struct'ı üzerinde çalışacak şekilde
devralır/işler.
pid_t pid = fork();
if (pid == 0) {
/* child: trigger the context teardown path that schedules the drain,
* then exit so its mm_struct is freed. */
_exit(0);
}
/* parent: continue Mali operations that invoke
* kbasep_os_process_page_usage_drain() during/after the child's exit.
* The synchronize_rcu() window in the drain path overlaps the child's
* mm_struct teardown. */
İki tarafı, drain mm free edilmiş descriptor'a işaret ederken çalışana kadar
race et. Reclaim et ve corrupt et:
/* 3. After the free, spray the kmalloc cache that backs mm_struct with a
* controllable object to reclaim the freed slot. */
spray_reclaim_objects();
/* 4. The dangling kbasep_add_mm_counter() write now lands in the reused
* object. Steer it toward a corruption that yields kernel R/W, then
* overwrite cred/SELinux state for root. */
Zafiyetli bir driver'da (Midgard r12p0-r32p0, Bifrost r0p0-r42p0, Valhall
r19p0-r42p0, 5th Gen r41p0-r42p0) beklenen davranış: KASAN build'leri
kbasep_os_process_page_usage_drain() / kbasep_add_mm_counter() içinde bir
use-after-free read/write raporlar. r43p0+ üzerinde kctx->process_mm lifecycle'ı
cross-process etkileşimini elemek için yeniden yapılandırıldı, böylece path
artık yabancı bir mm_struct'a dokunmaz.
Detection¶
kbasep_os_process_page_usage_drainveyaprocess_mmaccounting'ine atıf yapan KASAN use-after-free raporları doğrudan bir sinyaldir.- Bir Mali context canlıyken bir child process exit'inden sonra beklenmedik RSS
accounting delta'ları, confused-
mmpath'inin çalıştığını gösterebilir. - CVE-2023-4211 CISA Known Exploited Vulnerabilities kataloğunda (3 Ekim 2023'te eklendi) ve Google TAG / Project Zero tarafından hedefli saldırılarda ticari spyware tarafından exploit edildiği raporlandı.
Mitigation¶
- Mali Bifrost, Valhall ve 5th Gen Kernel Driver r43p0 veya sonrasına güncelle; Midgard kullanıcıları fix'li bir branch'e geçmeli.
- Ekim 2023 Arm fix'ini yansıtan Android security patch level'ının OEM tarafından kurulduğundan emin ol.