Adreno A7xx SDS->RB 权限绕过 (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
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
本页将一处真实世界的 Adreno A7xx 微代码逻辑漏洞 (CVE-2025-21479) 抽象为可复现的利用技术:滥用 Set Draw State (SDS) 中的 IB-level masking 以从非特权应用执行特权 GPU packets,pivot 到 GPU SMMU takeover,然后通过 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).
Background: IB levels, SDS and the $12 mask
- The kernel maintains a ringbuffer (RB=IB0). Userspace submits IB1 via CP_INDIRECT_BUFFER, chaining to IB2/IB3.
- SDS is a special command stream entered via CP_SET_DRAW_STATE:
- A6xx: SDS is treated as IB3
- A7xx: SDS moved to IB4
- Microcode tracks the current IB level in register $12 and gates privileged packets so they are only accepted when the effective level corresponds to IB0 (kernel RB).
- Bug: A7xx microcode kept masking $12 with 0x3 (2 bits) instead of 0x7 (3 bits). Since IB4 & 0x3 == 0, SDS was misidentified as IB0, allowing privileged packets from user-controlled SDS.
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 示例 (补丁将掩码切换为 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
利用概览
Goal: 从 SDS (misread as IB0) 下发特权 CP packets 来将 GPU SMMU 重新指向攻击者构造的 page tables,然后使用 GPU copy/write packets 实现任意物理 R/W。最后,通过 dirty pagetable 转向快速的 CPU 端 R/W。
高层流程
- 在共享内存中构造一个假的 GPU pagetable
- 进入 SDS 并执行:
- CP_SMMU_TABLE_UPDATE -> 切换到假的 pagetable
- CP_MEM_WRITE / CP_MEM_TO_MEM -> 实现写/读 原语
- CP_SET_DRAW_STATE with run-now flags(立即 dispatch)
通过假的 pagetable 实现 GPU R/W 原语
- 写:CP_MEM_WRITE 到攻击者选择的 GPU VA,该 VA 的 PTEs 映射到指定的 PA -> 任意物理写
- 读:CP_MEM_TO_MEM 将目标 PA 的 4/8 字节复制到用户空间共享缓冲区(对更大读取使用批量)
注意事项
- 每个 Android 进程会获得一个 KGSL context (IOCTL_KGSL_GPU_CONTEXT_CREATE)。切换 context 通常会在 RB 中更新 SMMU 表;该漏洞允许你在 SDS 中执行此操作。
- 过多的 GPU 流量可能导致 UI 黑屏和重启;读取很小(4/8B),且默认同步很慢。
构建 SDS 命令序列
- 将假的 GPU pagetable 喷入共享内存,确保至少有一个实例落在已知的物理地址(例如,通过 allocator grooming 和重复操作)。
- 构造一个 SDS buffer,按顺序包含:
- CP_SMMU_TABLE_UPDATE 指向假的 pagetable 的物理地址
- 一个或多个 CP_MEM_WRITE 和/或 CP_MEM_TO_MEM 包以使用新的映射实现 R/W
- 带有 run-now 标志的 CP_SET_DRAW_STATE
确切的包编码随固件而异;使用 freedreno’s afuc/packet docs 来组装 words,并确保驱动走的是 SDS 提交路径。
在 physical KASLR 下定位 Samsung kernel physbase
Samsung 在 Snapdragon 设备上会在已知区域内随机化内核物理基址。对预期范围进行暴力搜索,并查找 _stext 的前 16 个字节。
示例循环
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 端 kernel R/W(dirty pagetable)
GPU R/W 既慢且粒度小。通过破坏自身进程的 PTE 来切换到快速/稳定的原语(“dirty pagetable”):
Steps
- Locate current task_struct -> mm_struct -> mm_struct->pgd using the slow GPU R/W primitives
- mmap 两个相邻的 userspace 页面 A 和 B(例如在 0x1000)
- Walk PGD->PMD->PTE 来解析 A/B 的 PTE 物理地址(helpers: get_pgd_offset, get_pmd_offset, get_pte_offset)
- Overwrite B’s PTE to point to the last-level pagetable managing A/B with RW attributes (phys_to_readwrite_pte)
- 通过 B 的 VA 写入以修改 A 的 PTE 映射到目标 PFNs;通过 A 的 VA 读/写内核内存,并刷新 TLB 直到哨兵翻转
示例 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>
## 检测
- 遥测:如果 CP_SMMU_TABLE_UPDATE(或类似的特权 opcodes)出现在 RB/IB0 之外,尤其是在 SDS 中,则发出警报;监控异常的 4/8 字节 CP_MEM_TO_MEM 突发和过量的 TLB 刷新模式
## 影响
本地具有 GPU 访问权限的应用可以执行特权 GPU packets,劫持 GPU SMMU,实现任意内核物理/虚拟 R/W,禁用 SELinux 并在受影响的 Snapdragon A7xx 设备上(例如 Samsung S23)获得 root。严重性:高(内核被攻破)。
### See also
<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)!
> - **加入** 💬 [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**Telegram 群组**](https://t.me/peass) 或 **在** **Twitter** 🐦 **上关注我们** [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **通过向** [**HackTricks**](https://github.com/carlospolop/hacktricks) 和 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) GitHub 仓库提交 PR 来分享黑客技巧。
>
> </details>


