Adreno A7xx SDS->RB privilege bypass (GPU SMMU takeover to Kernel R/W)
Tip
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Ova stranica apstrahuje in-the-wild Adreno A7xx microcode logic bug (CVE-2025-21479) u reproducibilne tehnike eksploatacije: zloupotreba IB-level masking u Set Draw State (SDS) za izvršavanje privilegovanih GPU paketa iz neprivilegovane aplikacije, pivotiranje na GPU SMMU takeover i zatim na brzo, stabilno kernel R/W putem dirty-pagetable trika.
- Pogođeno: Qualcomm Adreno A7xx GPU firmware pre microcode fixa koji je promenio masking registra $12 sa 0x3 na 0x7.
- Primitive: Execute privileged CP packets (e.g., CP_SMMU_TABLE_UPDATE) from SDS, which is user-controlled.
- Ishod: Arbitrarno fizičko/virtuelno R/W kernel memorije, onemogućavanje SELinux-a, root.
- Preduslov: Sposobnost da se kreira KGSL GPU context i pošalju command buffers koji ulaze u SDS (normalna sposobnost aplikacije).
Pozadina: IB levels, SDS and the $12 mask
- Kernel održava ringbuffer (RB=IB0). Userspace podnosi IB1 putem CP_INDIRECT_BUFFER, chaining ka IB2/IB3.
- SDS je poseban command stream koji se ulazi putem CP_SET_DRAW_STATE:
- A6xx: SDS se tretira kao IB3
- A7xx: SDS je pomeren na IB4
- Microcode prati trenutni IB nivo u registru $12 i dopušta privilegovane pakete samo kada efektivni nivo odgovara IB0 (kernel RB).
- Bug: A7xx microcode je maskirao $12 sa 0x3 (2 bita) umesto 0x7 (3 bita). Pošto IB4 & 0x3 == 0, SDS je pogrešno identifikovan kao IB0, što je omogućilo privilegovane pakete iz user-controlled SDS.
Zašto 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
Primer Microcode diff-a (patch je postavio masku na 0x7):
@@ 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
Exploitation overview
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.
High-level chain
- Craft a fake GPU pagetable in shared memory
- Enter SDS and execute:
- CP_SMMU_TABLE_UPDATE -> preusmeri na fake pagetable
- CP_MEM_WRITE / CP_MEM_TO_MEM -> implementiraj write/read primitive
- CP_SET_DRAW_STATE with run-now flags (dispatch immediately)
GPU R/W primitives via fake pagetable
- Write: CP_MEM_WRITE to an attacker-chosen GPU VA whose PTEs you map to a chosen PA -> arbitrary physical write
- Read: CP_MEM_TO_MEM copies 4/8 bytes from target PA to a userspace-shared buffer (batch for larger reads)
Notes
- Each Android process gets a KGSL context (IOCTL_KGSL_GPU_CONTEXT_CREATE). Switching contexts normally updates SMMU tables in the RB; the bug lets you do it in SDS.
- Excessive GPU traffic can cause UI blackouts and reboots; reads are small (4/8B) and sync is slow by default.
Building the SDS command sequence
- Spray a fake GPU pagetable into shared memory so at least one instance lands at a known physical address (e.g., via allocator grooming and repetition).
- Construct an SDS buffer containing, in order:
- CP_SMMU_TABLE_UPDATE to the physical address of the fake pagetable
- One or more CP_MEM_WRITE and/or CP_MEM_TO_MEM packets to implement R/W using your new translations
- CP_SET_DRAW_STATE with flags to run-now
The exact packet encodings vary by firmware; use freedreno’s afuc/packet docs to assemble the words, and ensure the SDS submission path is taken by the driver.
Finding Samsung kernel physbase under physical KASLR
Samsung randomizes the kernel physical base within a known region on Snapdragon devices. Brute-force the expected range and look for the first 16 bytes of _stext.
Reprezentativna petlja
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;
}
}
Kada je physbase poznat, izračunajte kernel virtual pomoću linearne mape:
_stext = 0xffffffc008000000 + (Kernel Code & ~0xa8000000)
Stabilizacija ka brzom, pouzdanom CPU-side kernel R/W (dirty pagetable)
GPU R/W je spor i sa malom granularnošću. Pređite na brz/stabilan primitiv korumpiranjem sopstvenih PTE-ova procesa („dirty pagetable“):
Steps
- Locirajte current task_struct -> mm_struct -> mm_struct->pgd koristeći spore GPU R/W primitives
- mmap dve susedne userspace stranice A i B (npr. na 0x1000)
- Prođite kroz PGD->PMD->PTE da rešite fizičke adrese PTE-ova za A/B (helpers: get_pgd_offset, get_pmd_offset, get_pte_offset)
- Prepišite B-ov PTE da pokazuje na last-level pagetable koji upravlja A/B sa RW atributima (phys_to_readwrite_pte)
- Pišite preko B-ovog VA da mutirate A-ov PTE kako biste mapirali ciljne PFN-ove; čitajte/pisajte kernel memoriju preko A-ovog VA, prazneći TLB dok sentinel ne promeni vrednost
Primer 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>
## Otkrivanje
- Telemetrija: alarmirajte ako CP_SMMU_TABLE_UPDATE (ili slični privileged opcodes) pojavljuje izvan RB/IB0, naročito u SDS; pratite anomalne nalete 4/8-byte CP_MEM_TO_MEM i prekomerne TLB flush obrasce
## Uticaj
Lokalna aplikacija sa pristupom GPU-u može izvršiti privilegovane GPU pakete, preuzeti GPU SMMU, ostvariti proizvoljno kernel fizičko/virtuelno R/W, onemogućiti SELinux i dobiti root na pogođenim Snapdragon A7xx uređajima (npr. Samsung S23). Ozbiljnost: Visoka (kompromitacija kernela).
### Vidi takođe
<a class="content_ref" href="pixel-bigwave-bigo-job-timeout-uaf-kernel-write.md"><span class="content_ref_label">Pixel Bigwave Bigo Job Timeout Uaf Kernel Write</span></a>
## Reference
- [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]
> Učite i vežbajte AWS Hacking:<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;">\
> Učite i vežbajte GCP Hacking: <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;">
> Učite i vežbajte Azure Hacking: <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>Podržite HackTricks</summary>
>
> - Proverite [**planove pretplate**](https://github.com/sponsors/carlospolop)!
> - **Pridružite se** 💬 [**Discord grupi**](https://discord.gg/hRep4RUj7f) ili [**telegram grupi**](https://t.me/peass) ili **pratite** nas na **Twitteru** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Podelite hakerske trikove slanjem PR-ova na** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repozitorijume.
>
> </details>


