## https://sploitus.com/exploit?id=710FF1CA-34DF-52FC-B8FA-38964635FC08
# CVE-2026-43499 Failure Record: MT6985 Adaptation Attempt
> **Conclusion**: Spent 68M tokens, but failed to obtain root access.
> **Reason**: KernelSnitch’s timing attacks are unreliable on MTK Dimensity 9300; `CONFIG_PANIC_ON_OOPS=y` prevents trial and error.
> **This article records the entire debugging process for future reference.**
---
## Background
| 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 results in immediate restart |
| Exploit | [CyberMeowfia](https://github.com/NebuSec/CyberMeowfia) — CVE-2026-43499 (IonStack) |
| Source Code Tree | android_15.0_kernel_MT6985 (5.15.178) — Does not match device version (Source code is for android15 GKI; device runs with android13 GKI) |
---
## What We Did
### 1. Source Code Analysis → Extract Structure Offset
Extracted from `arch/arm64/include/asm/memory.h`, `include/linux/fs.h`, and `android/abi_gki_aarch64.xml`:
- **Memory Layout**: `KIMAGE_TEXT_BASE = 0xffffffc008000000`, `VA_BITS=39`, `DIRECT_MAP=256GB`
- **task_struct**: 36864 bits, fully parsed (ABI XML `layout-offset-in-bits`)
- **file_operations**: No `iopoll` (android13 GKI); IOCTL=0x48, open=0x68
- **cred**: `atomic_t usage` = 4 bytes, uid=0x04
- **struct page**: 64 bytes, `slab_cache=0x18`
Key discovery: **Source code is for android15 GKI; device is android13 GKI**—the difference in task_struct offset is 0x40~0x88 bytes; cannot copy the source code directly. ### 2. Firmware Decompression → Extract Symbols
```
OTA zip (8.3GB)
→ payload.bin (8.2GB)
→ payload_dumper → boot.img (96MB, v4 header)
→ LZ4 decompression → Image (50MB ARM64)
→ kallsyms-finder → 187810 symbols
```
Symbols extracted from two versions of the firmware (15.2.7.6 / 15.2.10.2)—the same symbol differs by 10KB~200KB between the two versions. **Must use the correct version.** ### 3. Disassembly Verification → Capstone Confirmation of Key Offsets
```
# rt_mutex_adjust_pi:
LDR x21, [x19, #0x8b0] → pi_blocked_on = 0x8b0 (Android 15 value; not applicable for frankel)
```
This confirms that the task_struct layout is for Android 15, not Frankel’s Android 13. ### 4. Compilation → Success
NDK r29, `make PROJECT=android_15.0_kernel_MT6985` → `preload.so` (150KB). ### 5. Execution → Repeated Crashes
```
[+] preload starting pid=25414
[+] p0 profile... All symbols loaded correctly
[-] KernelSnitch mm_struct leak failed ← Sometimes this line is missing (occasionally successful)
[+] slide child context route=pselect ← Slide KASLR leak in child process startup
[Kernel Panic] ← rt_mutex_adjust_prio_chain+0x1b0
```
Crash Instruction (Capstone):
```armasm
ldar w8, [x27] ; x27 = waiter->lock (loaded from [x28, #0x38])
; x27 is a garbage value → Page table not mapped → Translation fault
→ die() → Panic → Restart
```
---
## Why It Failed
### Root Cause 1: KernelSnitch is Unreliable on MTK
KernelSnitch is the entry point for the entire exploit—it exploits the **timing differences** in futex hash buckets to reveal the `mm_struct` address:
1. **Collision Detection** succeeded—5 collisions found at low thresholds
2. **Brute-force Matching** almost always fails—core issue lies in:
```
MT6985 has CONFIG_KASAN_HW_TAGS=y → Kernel uses MTE tags to mark slab allocations
The pointers to the mm_struct have KASAN tags → futex_hash is calculated based on tagged pointers
However, brute-force scans direct maps (untagged addresses) → Calculated hashes don’t match
Even with MTE tags, when traversing 0-14 combinations (15 total), on a system with VA_BITS=39
The tag bits (bits56-59) overlap with extended symbols → Some tag combinations produce invalid addresses → Missed detection
```
**Pixel devices don’t have CONFIG_KASAN_HW_TAGS, but this mechanism works on Pixel devices. MTK doesn’t work.**
### Root Cause 2: `CONFIG_PANIC_ON_OOPS` Is the Killer Issue
```
Pixel: Kernel OOPS → dump_stack → Continues running → Exploit can be retried
MT6985: Kernel OOPS → die() → Panic() → Instant restart → No trial and error space
A slight deviation in the π chain causes a complete failure. On Pixel, a slight deviation means “This time it didn’t work, try another address.”
```
And the bootloader is locked (`flash.locked=1`) → This option cannot be disabled when using a custom kernel. ### Root cause 3: Kernel version drift
Source tree: 5.15.178 android15 GKI
Device: 5.15.178-android13 (vivo vendor)
Although the major version numbers are both 5.15.178, the GKI branch is different (android13 vs android15), and the layouts of key structures like task_struct/cred are inconsistent. I tried switching between the frankel/android15 branches repeatedly, but ultimately had to rely on disassembly to find the correct offset. ---
## Adjustments attempted (none of them worked)
| Change | Purpose | Result |
|-------|---------|-------|
| `THRESHOLD_MULT` 10→5→3 | Reduce the collision detection threshold | Too many false positives with <5 |
| `APPENDED_FUTEXES` 4096→8192 | Increase the hash chain difference | No effect |
| `REPEAT_MEASUREMENT/AVERAGE` | Increase sampling accuracy | No effect |
| `MTE=1` | Allow brute-force to traverse tags | Slower, but fewer crashes |
| `MM_STRUCT_SZ` 0x500→0x400 | Correct the mm_struct stride | Necessary; actual size is 992 bytes according to ABI |
| `IDENTITY_END` 64GB→256GB | Expand the scan range | Too slow (MTE traversal); still no match |
| TASK offsets: android15↔frankel | Lock the correct offset | Disassembly confirmed for android15 |
| FOPS offsets: android15↔frankel | android13 has no iopoll | Use frankel |
---
## Current state of target.h
In `exploit/targets/android_15.0/kernel_MT6985/target.h`:
| Category | Confidence | Verification Method |
|-------|----------|--------------------|
| Memory layout | **Correct** | Calculated from memory.h + verification of kallsyms `_text` |
| Symbol offsets (22) | **Correct** | Extracted from boot.img (version 15.2.10.2) |
| Task_struct offset | **Correct** | ABI XML + capstone disassembly (pi_blocked_on=0x8b0) |
| FOPS offset | **Correct** | ABI XML (android13 layout, no iopoll) |
| CRED offset | **Pending verification** | ABI XML (may be affected by vendor OEM fields) |
**The assembly is correct, the execution works, but we’re stuck at the last step.**
---
## If you want to proceed further
### Required conditions (all must be met)
1. **Remove `CONFIG_PANIC_ON_OOPS`** – Either disable it by using a custom kernel (which requires unlocking the bootloader), or find a MT6985 device where this option is disabled by default.
2. **Fix KernelSnitch** – Need to adjust the cache timing calibration for MTK Dimensity 9300, or completely replace KernelSnitch with another mm_struct leakage method in the exploit.
### Possible alternatives
- `/proc/self/pagemap` – This device has its limits (returns zero).
- MTK-specific debugging interfaces (`/proc/mtk_*`) – Exist, but need further analysis.
- IOctl vulnerabilities in MTK camera/GPU drivers – Simpler way to gain privileges.
- Adapt the code to MTK variants in the community.
### Residual value of this repository
- `symbols/kallsyms_PD2241_15.2.10.2.txt` – Complete symbol table for 15.2.10.2; can be used by others directly.
- `device_config.txt` – Actual kernel configuration of the device; shows what changes have been made by the vendor.
- `exploit/targets/android_15.0/kernel_MT6985/target.h` – Structure offsets have been verified.
- `scripts/server_compile.py` – Automated compilation; can be recompiled quickly by changing parameters.
---
## Troubleshooting list (for future use)
1. **Decompressing files on Windows**: `tar -xf` may fail for large zips. Use Python `zipfile` or decompress manually.
2. **Protobuf version conflict in payload_dumper**: The generated `update_metadata_pb2.py` requires protobuf 5.x. Need to manually remove the `runtime_version` line.
3. **Segfault occurs when running with `/system/bin/linker64 /data/local/tmp/preload.so`**: Must use `/system/bin/linker64 /data/local/tmp/preload.so`.
4. **ABI XML is more accurate than source code**: `layout-offset-in-bits` is calculated by the compiler; 5000 bytes more accurate than manual counting.
5. **GKI branch affects layout**: TaskStructs differ between android13/14/15; offsets cannot be copied across branches.
6. **Symbol offsets differ with different firmware versions**: 15.2.7.6 and 15.2.10.2 differ by 10KB to 200KB.
7. **vivo vendor added many OEM fields**: `CONFIG_ANDROID_VENDOR_OEM_DATA=y`, `CONFIG_SCHED_INFO=y`, `CONFIG_RSC_*` → Deviate from the standard GKI.
8. **Tools for extracting symbols**: `boot.img → kernel.bin → LZ4 decompression → Image → kallsyms-finder → symbol table`.
---
## Timeline
```
07/28 Downloaded the CyberMeowfia repository and MT6985 source code
07/29 Analyzed the source code (memory.h, fs.h, ABI XML, various structures)
Unpacked the firmware (payload.bin → boot.img → Image)
Extracted symbols (kallsyms-finder → 187810 symbols)
Multiple rounds of compilation, crashes, and disassembly verification
5 automated retries → All failed
Written this article
-------------------------------------------
Total: ~68M tokens, 0 root shells
```
---
*2026-07-29, finished writing the article*
[source-iocs-preserved const=KASAN_HW_TAGS]