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-2026-43499-S26 — Android GKI 6.12 kernel exploit for CVE-2026-43499, chaining an rt_mutex rollback bug with pselect stack overwrite to gain root on Samsung and Pixel devices. | Kitploit
Tools/GitHubGitHub/sammyenigma/cve-2026-43499-s26
Android SecurityPrivilege EscalationMemory ForensicsPersistence MechanismsExploitationReverse EngineeringShellcodePost-ExploitationMobile Security

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
Payload Development
Binary Exploitation
GitHubsammyenigma/cve-2026-43499-s26

CVE-2026-43499-S26

Android GKI 6.12 kernel exploit for CVE-2026-43499, chaining an rt_mutex rollback bug with pselect stack overwrite to gain root on Samsung and Pixel devices.

View Repository
1441 month agoNot yet reviewed

CVE-2026-43499 — Android GKI 6.12 pselect / configfs kernel exploit

A Linux kernel exploit for the Android GKI 6.12 line (Samsung and Pixel devices) targeting CVE-2026-43499: a buggy remove_waiter() rollback in rt_mutex_start_proxy_lock() that uses current instead of waiter::task, leaving a waiter's pi_blocked_on pointing at its (later-popped) kernel stack rt_mutex_waiter. Combined with a pselect() fd_set stack overwrite and a consumer sched_setattr-driven fake rb_tree walk, it yields a deterministic kernel write primitive and full root.

The exploit runs as an LD_PRELOAD shared library (preload.so) and installs a root su daemon plus wallpaper as post-root artifacts.

Status: active development. The m1q (ZF1) target is the bring-up focus. The pipei tmp_page-uname bootstrap is the current active route: the walk is proven clean on-device (build #33: per-child seeded rt_mutex regions) and the full 168-candidate sweep is in progress. The configfs CFI route is a dead end on m1q (Rust ashmem — no injectable fops slot) and remains the route for C-ashmem targets. Per-target offsets vary by device — verify against the actual kernel binary before trusting them.

Vulnerable primitive (CVE-2026-43499)

When FUTEX_CMP_REQUEUE_PI requeues a waiter and the requeue's deadlock-detection chain walk returns -EDEADLK, __rt_mutex_start_proxy_lock() rolls back via remove_waiter() (rtmutex.c:1535). The rollback correctly dequeues the waiter from the wait tree but clears the requeue caller's pi_blocked_on instead of waiter->task->pi_blocked_on. The WAITER's pi_blocked_on stays dangling at its stack rt_mutex_waiter, which is popped once the futex times out.

After the timeout, the waiter's kernel stack region is reused: core_sys_select() copies the three fd_sets into that stack buffer (the nfds < 344 stack path on ZF1). A crafted fd_set word array re-materializes a fake rt_mutex_waiter / fake task / fake rt_mutex (with an rb_tree root whose pointers are controlled). A consumer thread then calls sched_setattr_tid(waiter) → rt_mutex_adjust_pi() → rb_erase_cached, which produces an arbitrary address write of a controlled value.

The whole primitive requires the PI chain cycle: the owner holds f_pi_target and also blocks on f_pi_chain (held by the waiter), so the chain walk hits owner → chain → waiter → target → owner and fails with -EDEADLK. Removing the cycle makes the requeue return success with zero kernel effect.

Exploitation chain

  1. Slide (KASLR) — leak the kernel base. Two routes:
    • tracefs sched_blocked_reason (m1q primary, on-device proven): a blocked kworker's saved return PC (stack_trace_save_tsk) is read from the ring buffer and compared against the compiled-in worker_thread offset. Runs before any boot_id-route words are used so data-alias write targets (data_addr() = p0 alias + slide_p0_offset) stay correct at a nonzero slide.
    • boot_id pselect route (fallback, slide-independent): a pselect write plants SLIDE_LOGGERS_0_1 into the boot_id sysctl data via a linear-map alias; the leaked value reconstructs stext. Parked on m1q: its W1 target (SLIDE_RANDOM_BOOT_ID_DATA_OFF, low physical RAM) has page-dependent writability — the slide moves the target across page boundaries per boot, so ~6/7 runs fault. Only exercised explicitly via SLIDE_FORCE_BOOTID (mechanism test) with the tree_pc/tree_left redirected to the sprayed page.
  2. KernelSnitch — spray mm_struct-sized objects and use a futex-hash collision to locate an mm_struct on the heap, leaking a kernel heap page address used as the fake-object spray base. Waiters are detached (not joined) on cleanup to avoid the kernel-stack OOM that crashed builds before #26.
  3. Main route — pipei tmp_page bootstrap (m1q, current focus) — the original configfs CFI route is a dead end on m1q: the Rust ashmem has no injectable static write_iter slot and the ASHMEM_SET_NAME heap object is a KVec whose layout does not line up with configfs_bin_write_iter's private_data. m1q pivots to a kmalloc write instead: reclaim the leaked mm order-3 block as pipe_inode_info objects and use the pselect W1 write (*(tree_left) = tree_pc) to overwrite a candidate's tmp_page slot (+0x90) with the UTS namespace page (init_uts_ns). A fanout write plants a marker name at the sysname offset and uname() reports "CatOS" — a verifiable kernel write with no static-object dependence. C-ashmem targets keep the configfs path.
  4. Pipe physrw — forge pipe buffer pages in the sprayed kernel page for physical read/write: cred patching, SELinux disable, and direct kernel memory manipulation.
  5. Root — patch the root child's cred (uid/gid/caps/SELinux SID), then preload.c installs the embedded su daemon (tmpfs-mounted into /apex/com.android.virt/bin, plus adbd-namespace and local variants) and swaps the wallpaper.

Walk shape (m1q, on-device proven)

The pselect fd_set words re-materialize a fake rt_mutex_waiter on the waiter's kernel stack; a consumer thread's sched_setattr_tid(waiter) walks it via rt_mutex_adjust_pi(). ZF1 word map (disasm-verified): PSELECT_WAITER_WORD_SHIFT = 0, word 12 = task (@+0x50), word 13 = lock (@+0x58), word 14 = wake_state (@+0x60 = 3). With a seeded fake rt_mutex the walk completes cleanly: [7]'s rb_erase W1 *(tree_left)=tree_pc / W2 *(tree_pc&~3+8)=tree_left are the only kernel writes; [11] (setprio / dequeue_pi) and the [9] wake are both skipped (local fake waiter at prio 100 keeps the stack node out of top-waiter). Every walk-entered completion since build #19 survives on-device; the deterministic crashes before that were an 8-byte payload placement error (SKB_DATA_DELTA), not a walk-body fault.

Stage 3 (pgd-swap bridge, static/build only)

Optional STAGE3=1 phase that forks a bridge child, swaps its mm->pgd to a staged fake page table (3-level: PGD→L1→L2, RX loop leaf + RW stack leaf), and lets the child run a register-only assembly blob that patches its own cred through a 2MB physical scan window — all-RAM phys R/W without the configfs/pipe primitives. Currently wired only into the m1q target and has not been run on-device.

Supported targets

41 targets in src/targets/<codename>-<build>/, each requiring at minimum a target.h (kernel symbol offsets, KIMAGE_TEXT_BASE, direct-map base, struct offsets). Pixel targets (comet, tokay, tegu, caiman, komodo, frankel, mustang, rango, stallion, blazer) override shared sources; Samsung targets (m1q-*) add device-specific logic.

make list-projects   # full list

Kernel struct layouts differ per device — offsets must be verified against the actual kernel binary / kallsyms for each target.

Build

Output: build/<PROJECT>/bin/preload.so (shared lib loaded via LD_PRELOAD).

# Default project
CC=clang make

# Specific device target (default: blazer-CP2A.260605.012)
CC=clang make PROJECT=m1q-BP4A.251205.006

# Without CC=clang: uses NDK if found ($NDK_ROOT / $ANDROID_NDK_HOME /
# $ANDROID_NDK_ROOT), otherwise host clang + Android sysroot
make PROJECT=m1q-BP4A.251205.006

# Show build configuration
make info

# Clean
make clean

The build embeds a PIE su_daemon binary (src/su_daemon.c, built to build/embed/su_daemon_aarch64_pie) and assets/wallpaper.webp into preload.so via src/su_blob.S / src/wallpaper_blob.S.

Run on device

Push the build outputs to /data/local/tmp, then run the exploit under LD_PRELOAD. Run WITHOUT tee on a live bring-up target — tee buffers its own stdio and loses the tail of the log on a kernel panic (exploit stdout is unbuffered, so redirecting straight to a file preserves every line):

Download Tool