CVE-2024-23373: Qualcomm Adreno GPU KGSL memory management flaw (chained for page-level UAF)¶
Başarısız bir IOMMU unmap'in page-table entry'lerini free edilmiş page'lere işaret eder bıraktığı bir KGSL memory-management kusuru; bir VBO bind race ve bir reference-counting hatasıyla (GPUAF chain'i) chain'lendiğinde, GPU'nun Android root için read/write yapabildiği page-level bir use-after-free verir.
Mechanism¶
Invariant: unmap, page'ler free edilmeden önce her PTE'yi tamamen yıkmalı
KGSL, GPU buffer'larını, physical page'leri bir kgsl_memdesc üzerinden GPU
IOMMU'suna map'lenen kgsl_mem_entry object'leri olarak yönetir. Lifecycle
invariant'ı, bir buffer free edildiğinde, onu kapsayan her IOMMU PTE'nin,
backing physical page'ler allocator'a iade edilmeden önce kaldırılması
gerektiğidir -- aksi halde GPU, kernel'in geri dönüştürebileceği memory'ye
canlı bir translation tutar.
CVE-2024-23373, GPUAF chain'indeki "unmap-failure / PTE-destruction" halkasıdır. Bir unmap operasyonu yarı yolda başarısız olduğunda (veya bir reference-counting hatası, bir mapping hâlâ onu referans ederken bir page'in free edilmesine neden olduğunda), driver IOMMU page table'larını tutarlı şekilde geri sarmaz. Sonuç, CVE-2023-33107 ile aynı tehlikeli son-state: zaten free edilmiş ve başka kernel allocation'larına verilmiş physical page'lere GPU virtual address'lerini hâlâ translate eden PTE'ler hayatta kalır.
Kendi başına bu bir mapping/reference tutarsızlığı; gücü kompozisyondan gelir. "GPUAF" araştırmasında şunlarla chain'lenir:
- CVE-2024-23380 -- başlangıçtaki freed-page koşulunu yaratan, VBO bind'deki bir race (bkz. cve-2024-23380-qualcomm-adreno-gpu-kgsl-vbo-mapping-race).
- bir reference-counting hatası --
kgsl_mem_entry/ page refcount'unu vakitsiz olarak sıfıra sürer.
Birlikte bir page-level use-after-free üretirler: GPU'nun bayatlamış
IOMMU PTE'leri üzerinden hâlâ okuyup yazabildiği free edilmiş physical
page'ler. O page'leri page table'lar veya kgsl_mem_entry/pipe_buffer
object'leri olarak reclaim etmek, GPU read/write'ını kernel read/write'a
çevirir. Bu, page-uaf'in IOMMU-side kuzeni ve
dirty-pagetable-page-table-data-only-attack'in
data-only tarzı.
Walkthrough¶
CVE-2024-23373 tek başına değil bir chain'in parçası olarak exploit edilir; aşağıdaki dizi onun nereye oturduğunu gösterir.
/* Core structures (from the GPUAF analysis). */
struct kgsl_mem_entry {
struct kref refcount;
struct kgsl_memdesc memdesc;
void *priv_data;
struct rb_node node;
unsigned int id;
struct kgsl_process_private *priv;
char metadata[KGSL_GPUOBJ_ALLOC_METADATA_MAX + 1];
};
struct kgsl_memdesc {
struct kgsl_pagetable *pagetable;
phys_addr_t physaddr;
uint64_t size;
struct rb_root_cached ranges; /* VBO binding tree */
struct mutex ranges_lock;
const struct kgsl_memdesc_ops *ops;
struct page **pages;
};
Adım 1 -- bir VBO oluştur ve Basic Memory Object'leri bind/unbind et, böylece unmap-failure / refcount path'i dangling IOMMU PTE'leri bıraksın:
int vbo = gpuobj_alloc(fd, size, KGSL_MEMFLAGS_VBO); /* IOCTL_KGSL_GPUOBJ_ALLOC */
/* race bind/unbind (CVE-2024-23380) so a backing page's refcount hits zero
* while the VBO still maps it; the failed/partial unmap (CVE-2024-23373)
* leaves the GPU PTE valid over the now-freed page. */
Adım 2 -- freed-page state'ini doğrula. GPUAF analizi temiz bir oracle not eder: tetikledikten sonra açık bir unbind yap. Bug başarılı olduysa VBO free edilmiş page'e erişimi korur; race kaybedildiyse unbind VBO'yu taze bir zero page'e geri çevirir ve sentinel kaybolur.
gpumem_unbind_ranges(fd, vbo, range);
if (gpu_read_u32(vbo_gpuaddr) == SENTINEL)
/* dangling PTE confirmed: page-level UAF live */;
Adım 3 -- reclaim ve escalate (VBO-race writeup'ıyla ortak): kernel free edilmiş page'leri geri çeksin diye memory pressure uygula, onları page table'lar veya kontrol edilebilir object'ler olarak reclaim et, sonra kernel memory'yi okuyup yazmak ve SELinux'u devre dışı bırakmak için GPU command paket'lerini kullan.
pressure_alloc_mb(LOTS); /* push kernel to reclaim KGSL pool pages */
reclaim_as_page_tables_or_objects(); /* freed page now backs kernel data */
gpu_write_region(target_gpuaddr, payload, len); /* kernel R/W -> root */
Zafiyetli firmware'de beklenen davranış: unmap edilmiş range'in GPU read'leri fault vermek yerine hâlâ canlı, geri dönüştürülmüş kernel data döner. Temmuz 2024 patched firmware'de unmap path'i tüm PTE'leri yıkar ve GPU free edilmiş range üzerinde fault verir.
Detection¶
- Bir VBO unbind'ı veya
kgsl_mem_entryfree'sinin hemen ardından gelen IOMMU/SMMU translation fault'ları yıkılmamış PTE'leri gösterir. - KGSL'de beklenmedik
kgsl_mem_entry/page refcount underflow'ları. - Man Yue Mo (GitHub Security Lab) tarafından 2023-12-18'de raporlandı; Qualcomm tarafından High olarak değerlendirildi. Black Hat USA 2024 / DEF CON 32'de sunulan GPUAF araştırmasının parçası.
Mitigation¶
- KGSL graphics driver'ı için Qualcomm'un Temmuz 2024 security bulletin patch'ini uygula.
- Android security patch level'ını 2024-07-05 veya sonrasında tut.