Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
cve-2025-21479_iqooneo8 — Local root exploit for CVE-2025-21479 (Adreno KGSL) on iQOO Neo8 (SM8475) - physical memory r/w, disables SELinux, spawns root shell | Kitploit
Tools/GitHubGitHub/qingizi7/cve-2025-21479_iqooneo8
Android SecurityPrivilege EscalationExploit FrameworksExploitationReverse EngineeringMobile SecurityHardware & IoT SecurityPayload DevelopmentBinary Exploitation

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
GitHubqingizi7/cve-2025-21479_iqooneo8

cve-2025-21479_iqooneo8

Local root exploit for CVE-2025-21479 (Adreno KGSL) on iQOO Neo8 (SM8475) - physical memory r/w, disables SELinux, spawns root shell

View Repository
631051 month agoNot yet reviewed

CVE-2025-21479 — Qualcomm Adreno GPU Privilege Escalation Exploit (SM8475 / iQOO Neo8)

Local privilege escalation proof-of-concept code targeting CVE-2025-21479, aimed at the Qualcomm Adreno GPU (KGSL) on the vivo V2301A (iQOO Neo8 / PD2301, Snapdragon 8+ Gen 1 / SM8475, Adreno A730, Android 14, GKI kernel 5.10).

In principle, the exploit drives the GPU's SMMU through KGSL's CP_SMMU_TABLE_UPDATE command, gaining arbitrary physical memory read/write capability, and then disables SELinux, locates kernel symbols, and obtains a root shell—all without flashing the device or relying on an unlocked bootloader.

For security research only on devices you own or are authorized to test.


What It Does

  1. GPU physical memory primitive. The access check in the Adreno A730 (eureka_panther) microcode (and $12, 0x3) is flawed and misclassifies Self-Draw-State (SDS) packets as RingBuffer (RB). Therefore, by submitting a forged CP_SMMU_TABLE_UPDATE inside an SDS block from user space, the GPU's TTBR0 can be overwritten, making the GPU page table point to an arbitrary physical page—from then on the GPU can read and write arbitrary physical memory.
  2. Stabilized read/write. Through stabilize_rw, the mapping is hardened into a 2 MB self-mapping region, supporting high-volume fast reads (fast_pread_bytes, etc.).
  3. Disable SELinux. Zero out the selinux_state.enforcing field in physical memory. Then dump the kernel image from the fixed physical base address 0xA8000000 (default limit 43 MB)— SM8475 has no physical KASLR—and parse the kallsyms structures directly from the raw dump (automatic endianness detection), so virtual KASLR does not matter either.
  4. root payload. Use a piece of AArch64 shellcode (prepare_kernel_cred(0) → commit_creds(), and disable seccomp) to patch __do_sys_capset. The forked child process calls capset() → becomes uid 0 → restores the overwritten kernel code → the child process re-executes your specified command in the u:r:shell:s0 domain (default sh). The kernel code ultimately matches byte-for-byte what it was before running.

Tested Device

Modelvivo V2301A (iQOO Neo8, codename PD2301, board taro)
SoCSM8475 (Snapdragon 8+ Gen 1) + Adreno 730
Android14 (UP1A.231005.007, SDK 34, qssi-user)
Kernel5.10.198-gki-gfb2f5774872c
SELinuxEnforcing (disabled at runtime by this tool)

See device_info.txt for full device information.

Repository Structure

├── 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

Usage

#推送exploit
adb push exploit /data/local/tmp/

#运行exploit
adb shell
chmod +x /data/local/tmp/exploit
/data/local/tmp/exploit

Click here for the detailed tutorial (it includes a one-click tool)

On success, you get a uid=0 shell, and SELinux is disabled for this session. After completing privilege escalation, the process re-executes argv[1..] (defaults to sh). Each run has a countdown ("pte wait 3 second") and a 43 MB kernel read progress ("Read X / 43 MB"). Privilege escalation succeeded, uid=0

Environment Variables

VariablePurpose
CHEESE_PHYADDR=<phys>Force a specific kernel physical base address (skips the built-in gPhyAddrs probe table).
CHEESE_ATTEMPT=<n>Use gPhyAddrs[n] instead of gPhyAddrs[0]; after a GPU initialization failure, maybe_retry automatically increments and retries.
CHEESE_SWAPPER_PG_DIR_OFF=<off>Skip the swapper_pg_dir scan and use this absolute offset directly.
CHEESE_READ_FULL_KERNEL=1Read the full kernel image (the default read limit is DEFAULT_KERNEL_SIZE_MB = 43 MB).
CHEESE_KALLSYMS_MAX_MB=<MB>Override the kallsyms read limit.
CHEESE_FORCE_MANUAL_PATCHFINDER=1Force the manual patchfinder fallback (init_cred, prepare_kernel_cred).
CHEESE_SKIP_GPU=1Skip the GPU read/write stage (for debugging only).
CHEESE_NO_RETRY=1Exit immediately on failure without retrying with a different attempt number.

Disabling vr.ko

Due to the special mechanism of vivo devices, on the iQOO Neo8 it must be disabled to keep root privileges stable (the specific principle is not explained here. Other vivo models and kernel versions may not be compatible; you need to extract vr.ko yourself and reverse engineer it). Before performing the following operations, make sure the current shell session has obtained root privileges.

#备份原始apanic

dd if="$(readlink -f /dev/block/by-name/apanic)" of=/sdcard/apanic_full.bin
#adb shell内执行
adb pull /sdcard/apanic_full.bin ./
#主机端执行

#禁用vr.ko(风险自行评估)
printf '\370\037\000\000\000\000\000\000\000\000\000\000' | dd of=$(readlink -f /dev/block/by-name/apanic) bs=1 seek=$(( $(blockdev --getsize64 /dev/block/by-name/apanic) - 65472 )) conv=notrunc && sync

If a cold reboot of the phone later causes root privileges to be lost, simply re-run the exploit and then perform the jailbreak

ReSukiSU Jailbreak (root privilege persistence)

$(find /data/app -type f -name "libksud.so" | grep resukisu) late-load --kmi android12-5.10

Porting to Other Devices

Device-related constants are located at the top of source/cheese.c:

  • KERNEL_PHYS_BASE — kernel physical base address (default 0xA8000000, SM8475)
  • IDMAP_PG_DIR_OFFSET — idmap_pg_dir offset (default 0x245a000)
  • selinux_state_offset — offset used to locate selinux_state (default 0x729030, actual physical address = idmap_pg_dir physical address + this offset)
  • gPhyAddrs[] — candidate physical base addresses to try in sequence
  • DEFAULT_KERNEL_SIZE_MB — fallback value / upper limit for kernel reads

Prerequisites: Adreno A730/A7xx series GPU (affected firmware), and the device system has not installed the security patch released by Qualcomm in June 2025, a kernel whose kallsyms can be parsed from the physical dump, and no physical KASLR.

FAQ

  • can't get GPU r/w — GPU initialization failed; wait first, and if it still fails, try CHEESE_ATTEMPT=1..n or manually specify CHEESE_PHYADDR; add CHEESE_NO_RETRY=1 when debugging a single attempt.
  • kallsyms parsing failed — first use CHEESE_READ_FULL_KERNEL=1 to read the full image (together with CHEESE_KALLSYMS_MAX_MB to increase the limit), then consider CHEESE_FORCE_MANUAL_PATCHFINDER=1.
  • This tool does not flash or persist anything: kernel code and page tables are restored before it finishes, and after a reboot the device is exactly the same as before it ran.

Acknowledgements

Download Tool