Adreno A7xx SDS->RB privilege bypass (GPU SMMU takeover to Kernel R/W)

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Bu sayfa, gerçek dünyada bulunan bir Adreno A7xx microcode mantık hatasını (CVE-2025-21479) tekrarlanabilir sömürü tekniklerine soyutlar: Set Draw State (SDS) içerisindeki IB-seviyesi maskelenmesini suistimal ederek ayrıcalıklı GPU paketlerini unprivileged bir uygulamadan çalıştırmak, GPU SMMU takeover’a pivot yapmak ve ardından dirty-pagetable hilesi ile hızlı, stabil bir kernel R/W elde etmek.

  • Etkilenen: Qualcomm Adreno A7xx GPU firmware, register $12 maskesini 0x3’ten 0x7’ye değiştiren microcode düzeltmesine kadar olan sürümler.
  • İlkel: SDS’den ayrıcalıklı CP paketlerini (ör. CP_SMMU_TABLE_UPDATE) çalıştırmak; SDS kullanıcı tarafından kontrol edilebilir.
  • Sonuç: İstediğiniz fiziksel/sanal kernel bellek R/W, SELinux devre dışı bırakma, root.
  • Önkoşul: Bir KGSL GPU context oluşturabilme ve SDS’ye giren command buffer’lar submit edebilme yeteneği (normal uygulama yetkisi).

Background: IB levels, SDS and the $12 mask

  • Kernel bir ringbuffer (RB=IB0) tutar. Userspace, CP_INDIRECT_BUFFER ile IB1 gönderir ve IB2/IB3’e zincirler.
  • SDS, CP_SET_DRAW_STATE ile girilen özel bir komut akışıdır:
  • A6xx: SDS IB3 olarak işlenir
  • A7xx: SDS IB4’e taşındı
  • Microcode, geçerli IB seviyesini register $12’de izler ve ayrıcalıklı paketleri yalnızca efektif seviye RB’ye (IB0) karşılık geldiğinde kabul edecek şekilde kısıtlar.
  • Hata: A7xx microcode, $12’yi 0x7 (3 bit) yerine 0x3 (2 bit) ile maskelemeye devam etti. IB4 & 0x3 == 0 olduğundan, SDS yanlışlıkla IB0 olarak tanımlandı ve kullanıcı kontrollü SDS’den gelen ayrıcalıklı paketlere izin verildi.

Why it matters:

A6XX                | A7XX
RB  & 3       == 0  |  RB  & 3       == 0
IB1 & 3       == 1  |  IB1 & 3       == 1
IB2 & 3       == 2  |  IB2 & 3       == 2
IB3 (SDS) & 3 == 3  |  IB3 & 3       == 3
|  IB4 (SDS) & 3 == 0   <-- misread as IB0 if mask is 0x3

Microcode diff örneği (yama maskeyi 0x7 olarak değiştirdi):

@@ CP_SMMU_TABLE_UPDATE
- and $02, $12, 0x3
+ and $02, $12, 0x7
@@ CP_FIXED_STRIDE_DRAW_TABLE
- and $02, $12, 0x3
+ and $02, $12, 0x7

İstismar genel bakış

Goal: From SDS (misread as IB0) issue privileged CP packets to re-point the GPU SMMU to attacker-crafted page tables, then use GPU copy/write packets for arbitrary physical R/W. Finally, pivot to a fast CPU-side R/W via dirty pagetable.

Yüksek seviyeli zincir

  • Paylaşılan bellekte sahte bir GPU pagetable oluşturun
  • SDS’ye girin ve çalıştırın:
  • CP_SMMU_TABLE_UPDATE -> sahte pagetable’e geçiş
  • CP_MEM_WRITE / CP_MEM_TO_MEM -> yazma/okuma ilkelilerini uygulayın
  • CP_SET_DRAW_STATE with run-now flags (hemen çalıştır)

Sahte pagetable ile GPU R/W ilkelikleri

  • Write: CP_MEM_WRITE to an attacker-chosen GPU VA whose PTEs you map to a chosen PA -> keyfi fiziksel yazma
  • Read: CP_MEM_TO_MEM copies 4/8 bytes from target PA to a userspace-shared buffer (batch for larger reads)

Notlar

  • Her Android süreci bir KGSL context alır (IOCTL_KGSL_GPU_CONTEXT_CREATE). Context’leri değiştirmek normalde RB’deki SMMU tablolarını günceller; bug ise bunu SDS içinde yapmanıza izin veriyor.
  • Aşırı GPU trafiği UI kararmalarına ve yeniden başlatmalara neden olabilir; okumalar küçüktür (4/8B) ve sync varsayılan olarak yavaştır.

SDS komut dizisini oluşturma

  • En az bir örneğin bilinen bir fiziksel adrese yerleşmesi için sahte bir GPU pagetable’ı paylaşılan belleğe spray edin (ör. allocator grooming ve tekrar ile).
  • Sırayla içerecek şekilde bir SDS buffer oluşturun:
  1. CP_SMMU_TABLE_UPDATE to the physical address of the fake pagetable
  2. One or more CP_MEM_WRITE and/or CP_MEM_TO_MEM packets to implement R/W using your new translations
  3. CP_SET_DRAW_STATE with flags to run-now

Tam paket kodlamaları firmware’e göre değişir; freedreno’s afuc/packet docs kullanarak kelimeleri birleştirin ve sürücünün SDS submission yolunun kullanıldığından emin olun.

Fiziksel KASLR altında Samsung kernel physbase’i bulma

Samsung, Snapdragon cihazlarda kernel fiziksel tabanını bilinen bir bölge içinde rastgeleleştirir. Beklenen aralığı brute-force ile tarayın ve _stext’in ilk 16 bytes’ını arayın.

Temsili döngü

while (!ctx->kernel.pbase) {
offset += 0x8000;
uint64_t d1 = kernel_physread_u64(ctx, base + offset);
if (d1 != 0xd10203ffd503233f) continue;   // first 8 bytes of _stext
uint64_t d2 = kernel_physread_u64(ctx, base + offset + 8);
if (d2 == 0x910083fda9027bfd) {           // second 8 bytes of _stext
ctx->kernel.pbase = base + offset - 0x10000;
break;
}
}

physbase bilindiğinde, kernel virtual’ı doğrusal eşleme ile hesaplayın:

_stext = 0xffffffc008000000 + (Kernel Code & ~0xa8000000)

Hızlı, güvenilir CPU tarafı kernel R/W’ye istikrarlı geçiş (dirty pagetable)

GPU R/W yavaş ve küçük granülitede. Kendi süreç PTE’lerinizi bozarak (“dirty pagetable”) hızlı/stabil bir primitive’e geçin:

Steps

  • Mevcut task_struct -> mm_struct -> mm_struct->pgd öğesini yavaş GPU R/W primitives kullanarak bulun
  • İki bitişik userspace sayfasını A ve B olarak mmap edin (ör. 0x1000’de)
  • A/B’nin PTE fiziksel adreslerini çözmek için PGD->PMD->PTE üzerinde yürüyün (yardımcılar: get_pgd_offset, get_pmd_offset, get_pte_offset)
  • B’nin PTE’sini, A/B’yi yöneten son seviyedeki pagetable’ı RW öznitelikleriyle gösterecek şekilde overwrite edin (phys_to_readwrite_pte)
  • Hedef PFN’leri map edecek şekilde A’nın PTE’sini değiştirmek için B’nin VA’sı üzerinden yazın; sentinel değişene kadar TLB’yi flush ederek A’nın VA’sı üzerinden kernel belleğini oku/yazın
Örnek dirty-pagetable pivot snippet ```c uint64_t *map = mmap((void*)0x1000, PAGE_SIZE*2, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); uint64_t *page_map = (void*)((uint64_t)map + PAGE_SIZE); page_map[0] = 0x4242424242424242;

uint64_t tsk = get_curr_task_struct(ctx); uint64_t mm = kernel_vread_u64(ctx, tsk + OFFSETOF_TASK_STRUCT_MM); uint64_t mm_pgd = kernel_vread_u64(ctx, mm + OFFSETOF_MM_PGD);

uint64_t pgd_off = get_pgd_offset((uint64_t)map); uint64_t phys_pmd = kernel_vread_u64(ctx, mm_pgd + pgd_off) & ~((1<<12)-1); uint64_t pmd_off = get_pmd_offset((uint64_t)map); uint64_t phys_pte = kernel_pread_u64(ctx, phys_pmd + pmd_off) & ~((1<<12)-1); uint64_t pte_off = get_pte_offset((uint64_t)map); uint64_t pte_addr = phys_pte + pte_off; uint64_t new_pte = phys_to_readwrite_pte(pte_addr); kernel_write_u64(ctx, pte_addr + 8, new_pte, false); while (page_map[0] == 0x4242424242424242) flush_tlb();

</details>

## Tespit ve sertleştirme

- Firmware/microcode: $12'i maskelendiği tüm yerleri 0x7 (A7xx) kullanacak şekilde düzeltin ve ayrıcalıklı paket gate'lerini denetleyin
- Driver: ayrıcalıklı paketler için etkin IB seviyesini doğrulayın ve bağlam başına izin listelerini zorunlu kılın
- Telemetry: CP_SMMU_TABLE_UPDATE (veya benzeri ayrıcalıklı opcodelar) RB/IB0 dışında, özellikle SDS'de görünürse alarm verin; 4/8-byte CP_MEM_TO_MEM'in anormal patlamalarını ve aşırı TLB flush desenlerini izleyin
- Kernel: pagetable meta verilerini sertleştirin ve kullanıcı PTE bozulma desenlerini tespit edin

## Etki

GPU erişimi olan yerel bir uygulama ayrıcalıklı GPU paketlerini çalıştırabilir, GPU SMMU'yu ele geçirebilir, rastgele kernel fiziksel/sanal R/W elde edebilir, SELinux'u devre dışı bırakabilir ve etkilenen Snapdragon A7xx cihazlarda (ör. Samsung S23) root elde edebilir. Ciddiyet: Yüksek (kernel kompromisi).

## References

- [CVE-2025-21479: Adreno A7xx SDS->RB privilege bypass to kernel R/W (Samsung S23)](https://xploitbengineer.github.io/CVE-2025-21479)
- [Mesa freedreno afuc disassembler README (microcode + packets)](https://gitlab.freedesktop.org/mesa/mesa/-/blob/c0f56fc64cad946d5c4fda509ef3056994c183d9/src/freedreno/afuc/README.rst)
- [Google Project Zero: Attacking Qualcomm Adreno GPU (SMMU takeover via CP packets)](https://googleprojectzero.blogspot.com/2020/09/attacking-qualcomm-adreno-gpu.html)
- [Dirty pagetable (archive)](https://web.archive.org/web/20240425043203/https://yanglingxi1993.github.io/dirty_pagetable/dirty_pagetable.html)

> [!TIP]
> AWS Hacking'i öğrenin ve pratik yapın:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> GCP Hacking'i öğrenin ve pratik yapın: <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
> Azure Hacking'i öğrenin ve pratik yapın: <img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training Azure Red Team Expert (AzRTE)**](https://training.hacktricks.xyz/courses/azrte)<img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
>
> <details>
>
> <summary>HackTricks'i Destekleyin</summary>
>
> - [**abonelik planlarını**](https://github.com/sponsors/carlospolop) kontrol edin!
> - **💬 [**Discord grubuna**](https://discord.gg/hRep4RUj7f) veya [**telegram grubuna**](https://t.me/peass) katılın ya da **Twitter'da** bizi **takip edin** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Hacking ipuçlarını paylaşmak için** [**HackTricks**](https://github.com/carlospolop/hacktricks) ve [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github reposuna PR gönderin.
>
> </details>