
CVE-2026-43499 exploit adapter for MT6985 MediaTek Dimensity 9300 (vivo PD2241)
Conclusion: Spent 68M tokens, didn't get root.
Reason: KernelSnitch timing attack is unreliable on MTK Dimensity 9300,CONFIG_PANIC_ON_OOPS=yleaves no room for trial and error.
**This article records the complete pitfall process for future reference to avoid the same traps.
| Item | Value |
|---|---|
| Device | vivo PD2241 (Dimensity 9300 / MT6985), Android 15 |
| Firmware | PD2241_A_15.2.10.2.W10.V000L1 |
| Kernel | 5.15.178-android13-8-gfb31f5bdd612-dirty |
| Bootloader | Locked (ro.boot.flash.locked=1) |
| SELinux | Enforcing |
| panic_on_oops | Enabled → any kernel OOPS = instant reboot |
| Exploit | CyberMeowfia — CVE-2026-43499 (IonStack) |
| Source tree | android_15.0_kernel_MT6985 (5.15.178) — does not match the device version (source is android15 GKI, device runs android13 GKI) |
Extracted from arch/arm64/include/asm/memory.h + include/linux/fs.h + android/abi_gki_aarch64.xml:
KIMAGE_TEXT_BASE = 0xffffffc008000000, VA_BITS=39, DIRECT_MAP=256GBlayout-offset-in-bits)iopoll (android13 GKI), IOCTL=0x48, open=0x68atomic_t usage = 4 bytes, uid=0x04slab_cache=0x18Key finding: the source is android15 GKI, the device is android13 GKI — task_struct offsets differ by 0x40~0x88 bytes, so the source cannot be blindly copied.
OTA zip (8.3GB)
→ payload.bin (8.2GB)
→ payload_dumper → boot.img (96MB, v4 header)
→ LZ4 解压 → Image (50MB ARM64)
→ kallsyms-finder → 187810 符号
Extracted symbols from two firmware versions (15.2.7.6 / 15.2.10.2) — the same symbol differs by 10KB~200KB between the two versions, you must use the right version.
# rt_mutex_adjust_pi 中:
LDR x21, [x19, #0x8b0] → pi_blocked_on = 0x8b0 (android15 值, 非 frankel)
This confirmed that the task_struct layout is the android15 branch, not frankel's android13.
NDK r29, make PROJECT=android_15.0_kernel_MT6985 → preload.so (150KB).
[+] preload starting pid=25414
[+] p0 profile ... 所有符号正确加载
[-] KernelSnitch mm_struct leak failed ← 有时没这条 (偶尔成功)
[+] slide child context route=pselect ← slide KASLR leak 子进程启动
[内核 panic] ← rt_mutex_adjust_prio_chain+0x1b0
Crashing instruction (capstone):
ldar w8, [x27] ; x27 = waiter->lock (从 [x28, #0x38] 加载)
; x27 值是垃圾 → 页表无映射 → translation fault
; → die() → panic → 重启
KernelSnitch is the entry point of the entire exploit — it leaks the mm_struct address through the timing difference of futex hash buckets:
MT6985 有 CONFIG_KASAN_HW_TAGS=y → 内核用 MTE 标签标记 slab 分配
mm_struct 的指针带了 KASAN tag → futex_hash 基于 tagged pointer 计算
但 bruteforce 扫描 direct map (untagged 地址) → 算出来的 hash 对不上
即使加上 MTE tag 遍历 (0-14 共 15 种), 在 VA_BITS=39 的系统上
tag 位 (bit56-59) 与符号扩展位重叠 → 有些 tag 组合产生无效地址 → 漏检
Pixel devices don't have KASAN_HW_TAGS, so this mechanism works there. MTK doesn't.
CONFIG_PANIC_ON_OOPS Is the KillerPixel: 内核 OOPS → dump_stack → 继续跑 → exploit 可重试
MT6985: 内核 OOPS → die() → panic() → 秒重启 → 无试错空间
π 链破坏稍有偏差就全盘崩,Pixel 上偏差了只是"这次没成功,换组地址再来"。
Additionally, the bootloader is locked (flash.locked=1) → cannot flash a custom kernel to remove this option.
源码树: 5.15.178 android15 GKI
设备: 5.15.178-android13 (vivo vendor)
Although both major version numbers are 5.15.178, the GKI branches differ (android13 vs android15), and the layouts of key structs such as task_struct/cred are inconsistent. After repeatedly switching between the frankel and android15 offset sets, it was ultimately pinned down by disassembly.
In exploit/targets/android_15.0_kernel_MT6985/target.h:
It assembles fine and runs, but loses in the last mile.
CONFIG_PANIC_ON_OOPS — either flash a custom kernel (requires unlocking the bootloader), or find an MT6985 device with this option disabled by default/proc/self/pagemap — restricted on this device (returns all zeros)/proc/mtk_*) — exist but need further analysissymbols/kallsyms_PD2241_15.2.10.2.txt — complete 15.2.10.2 symbol table; later users can use it directlydevice_config.txt — the device's actual kernel config, showing what the vendor changedexploit/targets/android_15.0_kernel_MT6985/target.h — struct offsets verifiedscripts/server_compile.py — automated compilation, rebuilds quickly after changing parameterstar -xf may fail on large zips; use Python zipfile or manually extract firstupdate_metadata_pb2.py requires protobuf 5.x; you need to manually delete the runtime_version import line./preload.so directly will segfault: you must use /system/bin/linker64 /data/local/tmp/preload.solayout-offset-in-bits is computed by the compiler, 100x more accurate than manually counting 5000 bytesCONFIG_ANDROID_VENDOR_OEM_DATA=y, CONFIG_SCHED_INFO=y, CONFIG_RSC_* → deviates from standard GKI07/28 下载 CyberMeowfia 仓库 + MT6985 源码
07/29 源码分析 (memory.h, fs.h, ABI XML, 各种 struct)
固件解包 (payload.bin → boot.img → Image)
符号提取 (kallsyms-finder → 187810 符号)
多轮编译 + 多轮崩溃 + 反汇编验证
5 次自动重试 → 全部失败
写成这篇
-------------------------------------------
总计: ~68M tokens, 0 root shells
2026-07-29, lived to tell the tale
| Change | Purpose | Result |
|---|
THRESHOLD_MULT 10→5→3 | Lower collision detection threshold | Too many false positives below 5 |
APPENDED_FUTEXES 4096→8192 | Increase hash chain difference | No effect |
REPEAT_MEASUREMENT/AVERAGE | Increase sampling precision | No effect |
MTE=1 | Make bruteforce iterate over tags | Slower, but crashes actually decreased |
MM_STRUCT_SZ 0x500→0x400 | Fix mm_struct stride | Necessary, ABI is actually 992 bytes |
IDENTITY_END 64GB→256GB | Expand scan scope | Too slow (MTE iteration), still doesn't match |
| TASK offsets: android15↔frankel | Pin down the correct offsets | Disassembly confirms android15 |
| FOPS offsets: android15↔frankel | android13 has no iopoll | Use frankel |
| Category | Confidence | Verification Method |
|---|
| Memory layout | Correct | memory.h calculation + kallsyms _text verification |
| Symbol offsets (22) | Correct | Extracted from 15.2.10.2 boot.img |
| task_struct offsets | Correct | ABI XML + capstone disassembly (pi_blocked_on=0x8b0) |
| FOPS offsets | Correct | ABI XML (android13 layout, no iopoll) |
| CRED offsets | To be verified | ABI XML (may be affected by vendor OEM fields) |
boot.img → kernel.bin → LZ4 解压 → Image → kallsyms-finder → 符号表