## https://sploitus.com/exploit?id=C749C9BF-21A8-56DF-8C76-F0A96A5EC766
# CVE-2026-43499 (GhostLock) β XRing O1 Exploit Research
> Target: Xiaomi Pad 7 Ultra (jinghu)/Xiaomi 15S Pro (dijun), XRing O1 SoC
> Kernel: 6.6.77-android15-8-g5770c661275f-abogki443185593-4k
> Reference: Littlenine Enneaβs dijun case study
> Nature: Kernel security research / Vulnerability exploitation and adaptation
## Attack Chain
```
[1] kernelsnitch leaks the mm_struct (futex hash side channel)
β No device interface dependency, pure side channel
[2] prepare_good_kernel_page: Heap spraying (fake_task/fake_w0/fake_fops)
β skb spray to the kernel SLUB mechanism
[3] futex_wait_requeue_pi leaves a dangling pi_blocked_on (stack UAF)
β rt_mutex_cleanup_proxy_lock skips remove_waiter
[4] pselect reuses the same stack; core_sys_select overrides the waiter field
β waiter->lock = &pselect_user_lock (user space, PAN-negative)
[5] consumer sched_setattr triggers rt_mutex_adjust_prio_chain
β PI chain: waiterβlockβowner(fake_task)βfake_w0.pi_tree
[6] rb_insert writes *(target)=value (write at arbitrary address)
β write_left = target-8, write_pc = value
[7] Writing task->cred = init_cred + selinux_enforcing=0 β root
## Real-machine testing progress (2026-07-18)
Stage-by-stage testing (test_minimal.so, STAGE 1-7):
| Stage | Test Content | Result |
|---|---|---|
| STAGE 1 | Basic initialization (disable_rseq/set_limit/pin_to_core) | OK |
| STAGE 2 | Futex basics (FUTEX_LOCK_PI/UNLOCK_PI) | OK |
| STAGE 3 | kernelsnitch_setup (cpu_count=10) | OK |
| STAGE 4 | clone_leak_child (find_collisions) | OK |
| STAGE 5 | Brute-force leak of mm_struct | OK β Successful leak |
| STAGE 6 | prepare_good_kernel_page (spray) | OK β Page prepared |
| STAGE 7 | run_main_route_threads (PI chain triggered) | OK β Consumer succeeded 40 times |
**Example of mm_struct leak caused by kernelsnitch**: ffffff80186c5500, ffffff8109969400, ffffff818fe72d00
**PI chain trigger log**:
```
pselect returned attempt=1 ret=0 errno=0 calls=40 success=40 delay=50000
```
## Current bottlenecks
### 1. Values written by the PI chain are not write_pc (most critical)
The PI chain trigger was successful (consumer executed 40 times for sched_setattr), but the write did not take effect (SELinux remained Enforcing). Reason: The value written by rb_insert might be **the stack address of waiterβs pi_tree_entry** (stack address, not 0), not write_pc. Test: `set_pselect_write(SELINUX_ENFORCING-8, 0, 0)` expected `*selinux_enforcing=0`, but SELinux remains Enforcing. Need to disassemble the `rb_insert` part of `rt_mutex_adjust_prio_chain` (0xffffffc081052868) to confirm the actual written value.
### 2. From mm_struct to task_struct (reading mm->owner)
kernelsnitch leaked the mm_struct address. To write `task->cred`, the task_struct address is required, which involves reading mm_struct + 0x408 (mm->owner). However, all known kernel read paths are unavailable:
- configfs_read_once has a bug (see pitfall)
- `/dev/ashmem` is blocked by SELinux (Permission denied)
- `/proc/self/stat` has kstkesp=0 (kptr_restrict)
- BPF/debugfs is unreadable
Available resource: `/dev/uhid` (crw-rw-rw-, readable by everyone) β pending research
### 3. `/dev/ashmem` blocked by SELinux
`/dev/ashmem` has permissions 666, but SELinux blocks shell domain access. This prevents verification of the configfs path through fops. Direct writing of `cred` does not require ASHM verification, but reading `mm->owner` does.
## Pitfalls encountered
### Pitfall 1: Configfs_read_once failure is not a fix for Android 16
Disassembly of `configfs_bin_read_iter` (0xffffffc080488c9c) confirms:
- Correct offsets for CFG_* fields (0x50/0x58/0x60/0x64 match exactly)
- The failure is due to a code bug: setting needs_read_fill=0 and not setting buffer_size results in 0
- This bug exists on Pixel devices as well; `configfs_read_once` may never succeed
### Pitfall 2: Route deviation (fops hijacking vs. cred direct writing)
- **dijun** uses cred direct writing: `mm leaked` β two walks of `write_task` β `cred/real_cred=init_cred`.
- **jinghu** uses fops hijacking: writes to `ashmem_misc_fops` β verifies with `configfs` β leaks `kernel_base` β installs `root`.
- The fops route depends on `configfs`; cred direct writing is simpler.
### Pitfall 3: `page_base=0` issue
In STAGE 6, `page_base` is set, but in STAGE 7, `do_pselect_fake_lock_route` sees `0`. The reason is unclear (possibly multi-threaded visibility or compiler optimizations). Solution: Reimplemented `prepare_good_kernel_page` in STAGE 7.
### Pitfall 4: `pr_error` calls `exit(-1)`
When SYSCHK fails, `pr_error` calls `exit(-1)`, causing the process to exit after `ashmem_open` fails, and subsequent results cannot be seen. Solution: Redefine `pr_error` to not exit, or modify `open_ashmem_device` to not involve SYSCHK.
### Pitfall 5: `rt_mutex_waiter` layout
Disassembly verification shows that `pi_tree_entry` is at `+0x28` (not `+0x18`), with additional `prio/deadline` fields. `fake_task.pi_blocked_on` must point to the start of the `fake_w0` structure (not `pi_tree_entry`), otherwise the second read of the `lock` field is incorrect.
### Pitfall 6: `psselect` does not block
`readfds` is all zero, and `exceptfds=NULL` β `do_select` returns immediately with `ret=0` without checking any files. Fix: Set `exceptfds` to `pipe read end`, making `psselect` block until a timeout occurs.
### Key data
- Addresses (KASLR=0, vmlinux β runtime minus 0xc080000000)
- `KIMAGE_TEXT_BASE = 0xffffffc080000000`
- `init_task = 0xffffff80020de280`
- `init_cred = 0xffffff80020f0548`
- `selinux_state = 0xffffff8002315f68`
- `ashmem_misc_fops = 0xffffff800223b5e8`
### `task_struct` offsets
- `cred=+0x818`, `real_cred=+0x820`, `pi_blocked_on=+0x938`
- `pi_waiters=+0x920`, `real_parent=+0x628`, `comm=+0x830`
### `mm_struct` offset
- `owner=+0x408` (MM_OWNER_OFF)
### `rt_mutex_waiter` layout (disassembly verification)
- `+0x00 tree_entry` (rb_node 24B)
- `+0x18 prio` (u32)
- `+0x20 deadline` (u64)
- `+0x28 pi_tree_entry` (rb_node 24B) β used for PI tree traversal
- `+0x40 pi_prio` (u32)
- `+0x50 task` (ptr)
- `+0x58 lock` (ptr) β key field
### Writing primitives
- `set_pselect_write(target-8, value, 0)`
- `fake_w0.pi_tree.rb_left = target-8`
- `fake_w0.pi_tree.__rb_parent_color = value`
- `PI chain rb_insert: *(target) =???` (to be confirmed whether itβs `value` or stack address)
### Key functions in disassembly
- `ashmem_open` = `0xffffffc080c7af5c` (struct ashmem_area=0xdc0, name@+0x0)
- `configfs_bin_read_iter` = `0xffffffc080488c9c`
- `configfs_read_iter` = `0xffffffc080488978`
- `rt_mutex_adjust_prio_chain` = `0xffffffc081052868`
- `rt_mutex_cleanup_proxy_lock` = `0xffffffc081052634`
## Pending tasks (actions needed)
### Priority 1: Confirming the value written in the PI chain
Analyze the `rb_insert` part of `rt_mutex_adjust_prio_chain` to determine whether the written value is `write_pc` or the stack address. This determines whether any value can be written.
### Priority 2: Solving the issue with reading `mm->owner`
Find a kernel reading method that doesnβt rely on `configfs/ashmem`. Read from `mm_struct+0x408` to get the `task_struct`. Candidates: `/dev/uhid`, `perf_event`, `eBPF`.
### Priority 3: Child mm β parent task
`kernelsnitch` runs in `clone_leak_child`, leaking the child mm. To write the parent cred, read from `child_task->real_parent(+0x628)` to get the parent `task_struct`. Or change `kernelsnitch` to run on the parent.
### Priority 4: Multiple walks (slot mechanism)
`dijun` uses two walks (`slot_idx=1` writes `real_cred`, `slot_idx=2` writes `cred+selinux`). The slot mechanism needs to be implemented.
### Priority 5: Crash at #0x800
The `rt_mutex_setprio` function triggers a bug when the `pi_blocked_on` path is not empty (about 20 rounds). `dijun` avoids this by using `csettle_us=500` (microsecond timing).
## Pending tasks (actions needed)
## File List
```
share-poc-XRing-O1/
βββ README.md Project overview (attack chain/progress/holes/critical data/tasks)
βββ RESEARCH_NOTES.md Research notes (bug principles/technical approach/breakthroughs)
βββ docs/
β βββ findings.md Summary of key findings (configfs bug/kernelsnitch work/PI chain write issues)
βββ src/ Full source code (compilable)
β βββ test_minimal.c Phase-by-phase test programs (STAGE 1-7: isolation/panic points)
β βββ main_cred.c Cred direct writing framework (run_exploit 3 times: walk through cred writing)
β βββ target.h Jinghu offset configuration (address/struct offsets)
β βββ common.h Core header files (global variables declarations/macro definitions/extern declarations)
β βββ util.c kernelsnitch encapsulation + prepare_kernel_page + configfs_read_once
β βββ fops.c do_pselect_fake_lock + PI chain triggering + cfi verification
β βββ slide.c KASLR bypass (boot_id writing verification)
β βββ pipe.c Pipe phase (install_pipe_physrw)
β βββ root.c install_android_root (root installation after privilege escalation)
β βββ offset.h Target configuration entry point (include target.h)
β βββ su_daemon.c su daemon (root shell service)
β βββ su_blob.S Embedded su_daemon binary (.incbin, requires build/embed/resources)
β βββ wallpaper_blob.S Embedded wallpaper binary (.incbin, requires assets/resources)
β βββ kernelsnitch/ Core implementation of kernelsnitch leak (futex hash side channel)
β βββ kernelsnitch.h Complete implementation of mm_struct leak (450 lines, brute-force search)
β βββ futex_hash.h Futex hashing function (hash bucket calculation)
β βββ timeutils.h Time measurement tools (rdtsc etc.)
β βββ utils.h Macros for pr_info/pr_error/SYSCHK etc.
βββ disasm/ Disassembly of key functions (extracted from vmlinux_extracted)
β βββ chain_disasm.txt β rt_mutex_adjust_prio_chain (core of PI chain! Confirm rb_insert write value)
β βββ do_select_disasm.txt do_select (pselect stack layout, waiter coverage)
β βββ do_select_full_disasm.txt Full disassembly of do_select
β βββ core_sys_select_disasm.txt core_sys_select (register overwriting of waiter field)
β βββ futex_requeue_full.txt Full process of futex_wait_requeue_pi (stack UAF trigger)
β βββ futex_wait_requeue_pi_full.txt futex_wait_requeue_pi (vulnerability trigger point)
β βββ adjust_pi_disasm.txt rt_mutex_adjust_pi (entry of PI chain)
β βββ refs/ Reference data
β βββ kallsyms.txt Kernel symbol table (766 bytes, some key symbols)
β βββ kernel_config.txt Kernel configuration (219KB, extracted from /proc/config.gz)
```
### Compilation Instructions
The.incbin resources for su_blob.S/wallpaper_blob.S (build/embed/su_daemon_aarch64_pie, assets/wallpaper.webp) are not included in the repository. These resources need to be obtained from the CyberMeowfia upstream (IonStack/CVE-2026-43499/exploit/). The compilation command is as follows:
```bash
# Required to be in the CyberMeowfia/exploit directory (incbin resources provided)
NDK=android-ndk-r27d/toolchains/llvm/prebuilt/windows-x86_64
clang --target=aarch64-linux-android35 --sysroot=$NDK/sysroot \
-O2 -fPIC -I src -DTARGET_CONFIG_H="targets/jinghu/target.h" \
src/test_minimal.c src/main.c src/util.c src/slide.c src/fops.c \
src/pipe.c src/root.c src/su_blob.S src/wallpaper_blob.S \
-shared -o test_minimal.so -pthread -fuse-ld=lld
```
## Contact
Those with research interests or ideas are welcome to discuss. Key contact points: **Confirmation of rb_insert write values in the PI chain + kernel reading of mm->owner**. ---
*This research is solely for security research and defense purposes.*