Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,7 @@
- [Adreno A7xx Sds Rb Priv Bypass Gpu Smmu Kernel Rw](binary-exploitation/linux-kernel-exploitation/adreno-a7xx-sds-rb-priv-bypass-gpu-smmu-kernel-rw.md)
- [Af Unix Msg Oob Uaf Skb Primitives](binary-exploitation/linux-kernel-exploitation/af-unix-msg-oob-uaf-skb-primitives.md)
- [Arm64 Static Linear Map Kaslr Bypass](binary-exploitation/linux-kernel-exploitation/arm64-static-linear-map-kaslr-bypass.md)
- [Futex PI UAF to Pipe Physical R/W and Workqueue Execution](binary-exploitation/linux-kernel-exploitation/futex-pi-uaf-pipe-buffer-workqueue-usermodehelper.md)
- [Ksmbd Streams Xattr Oob Write Cve 2025 37947](binary-exploitation/linux-kernel-exploitation/ksmbd-streams_xattr-oob-write-cve-2025-37947.md)
- [Pixel Bigwave Bigo Job Timeout Uaf Kernel Write](binary-exploitation/linux-kernel-exploitation/pixel-bigwave-bigo-job-timeout-uaf-kernel-write.md)
- [Linux kernel exploitation - toctou](binary-exploitation/linux-kernel-exploitation/posix-cpu-timers-toctou-cve-2025-38352.md)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Futex PI UAF to pipe physical R/W and workqueue execution

{{#include ../../banners/hacktricks-training.md}}

This page abstracts the **GhostLock** Android chain (CVE-2026-43499): a futex priority-inheritance lifetime bug is converted into a constrained pointer write, CFI-compatible file operations and forged `pipe_buffer` entries provide physical memory R/W, and a forged workqueue item reaches usermode-helper execution when protected credentials cannot be patched.<sup>[[1]](#references)[[2]](#references)[[3]](#references)</sup>

## Primitive ladder

The original chain and the Samsung port use the following progression; offsets, syscall frame depth, reclaim objects, physical base, and usable workqueue are build-specific.<sup>[[1]](#references)[[2]](#references)</sup>

```text
futex PI lifetime race -> dangling waiter state
pselect stack reclaim -> fake rt_mutex_waiter
rb-tree erase -> constrained aligned pointer write
boot_id ctl_table anchors -> KASLR slide
CFI-compatible f_op substitution -> constrained virtual R/W
forged pipe_buffer.page -> arbitrary physical R/W
forged work_struct/subprocess_info -> privileged usermode helper
```

### Reclaiming the waiter and obtaining a write

After the futex PI race leaves stale `rt_mutex_waiter` state in the blocked task, reclaim the old kernel-stack frame with a syscall that copies controllable data deeply enough into its stack frame. The Android chain uses `pselect()` and its copied `fd_set` bitmaps; other builds may require a different syscall after measuring the freed frame. Forge the waiter's `tree`/`pi_tree` RB nodes plus safe `task` and `lock` pointers so unlinking the node makes RB-tree erase write one chosen pointer to a constrained aligned address.<sup>[[1]](#references)</sup>

Treat this as a **single pointer-sized write per successful race**, not arbitrary R/W. Repeat the race for independent targets and validate every dereferenced fake field because a malformed waiter normally crashes before the useful erase operation.<sup>[[1]](#references)</sup>

### KASLR oracle and CFI-compatible file operations

A useful first target is a readable sysctl's `ctl_table.data`. Repointing the `boot_id` entry can make its normal proc handler disclose a slid kernel pointer. On the Samsung port, accepting a candidate only when the `procname`, `data`, and `proc_handler` anchors all agree on the same slide avoids false positives across a very large arm64 slide range.<sup>[[1]](#references)[[2]](#references)[[3]](#references)</sup>

With kCFI enabled, replacing a file operation with an arbitrary function is insufficient: the indirect-call signature must match. The original chain replaces ashmem `read_iter`/`write_iter`-style entries with configfs handlers sharing `ssize_t (struct kiocb *, struct iov_iter *)`, yielding constrained virtual reads and writes without violating the CFI type check.<sup>[[1]](#references)</sup>

### Upgrading `pipe_buffer.page` to physical R/W

Locate or reclaim a pipe ring, then use the constrained write to replace selected `pipe_buffer.page` pointers with `struct page *` values for chosen PFNs. Ordinary pipe reads and writes now transfer bytes to or from those pages; a known vmemmap layout or a discovered physical-to-`struct page` transform makes the primitive addressable across physical memory.<sup>[[1]](#references)[[2]](#references)</sup>

Before trusting the channel, verify the target profile against the exact kernel image. The public port uses kallsyms plus embedded BTF to audit `pipe_inode_info`, `pipe_buffer`, `file`, `workqueue_struct`, `pool_workqueue`, `worker_pool`, `work_struct`, and `subprocess_info` layouts instead of copying offsets from another device or firmware.<sup>[[2]](#references)[[3]](#references)</sup>

## Workqueue/user-mode-helper endgame

Hypervisor-backed data protection can silently discard otherwise valid stores to `cred`, task-slab, or SELinux state. In that situation, avoid a credential-patching endgame and instead make an existing worker execute `call_usermodehelper_exec_work`; the helper inherits privileged kernel/init credentials without modifying the protected credential objects.<sup>[[2]](#references)[[3]](#references)</sup>

A robust forged-work installation performs these checks before linking anything into a live pool:<sup>[[2]](#references)[[3]](#references)</sup>

1. Read the target workqueue pointer and traverse its `pwqs` list (or a validated `dfl_pwq` for an unbound queue) to a `pool_workqueue` and `worker_pool`.
2. Validate pointer ranges and relationships such as `pwq->wq == wq`, then sanity-check `work_color`, `refcnt`, `nr_active`, `max_active`, and the pool work-list links.
3. Place a build-correct `subprocess_info` in kernel-accessible memory. Its embedded `work_struct.func` points to the slid `call_usermodehelper_exec_work`; `path`, `argv`, and `envp` point to stable kernel-accessible strings and arrays.
4. Encode `work_struct.data` with the selected PWQ and color, link `work.entry` into `worker_pool.worklist`, and update the matching PWQ accounting fields consistently.
5. Wake the chosen pool with legitimate work. The demonstrated port creates a `ptmx` allocation/free storm so normal queued work wakes a worker that also consumes the forged entry.

The helper can execute a small script such as `/system/bin/sh umh.sh`, create a root marker, and launch a restricted command channel. Start the daemon before slow evidence collection or repeated `sync` calls, and persist its exit status and stderr because helper stdout and rate-limited audit output are unreliable debugging channels.<sup>[[2]](#references)</sup>

## Runtime object discovery without perf leaks

When perf-based object leaks are blocked or too slow, start at `init_task.tasks.prev`, subtract the build's `task_struct.tasks` offset, and walk the global list backward until `tgid` matches the exploit process. From `task_struct.files`, follow `files_struct.fdt -> fdtable.fd`, inspect each `struct file`, and find the ashmem/configfs-backed descriptor used for virtual writes.<sup>[[2]](#references)[[3]](#references)</sup>

Bound every walk, require canonical/direct-map pointers, validate both list directions where possible, and reject unexpected TGIDs or `f_op` values. A corrupt list node should abort the attempt rather than becoming a second uncontrolled kernel write.<sup>[[2]](#references)</sup>

## Cleaning forged pipe slots without a panic

A forged pipe slot can reference a reserved kernel-image page that never received `get_page()`. Pipe teardown then calls `anon_pipe_buf_release -> __folio_put` on a zero-refcount reserved page; with `panic_on_oops=1`, the resulting bad-page warning resets the device.<sup>[[2]](#references)</sup>

Use two independent cleanup layers:<sup>[[2]](#references)</sup>

- **Descriptor holder:** an `atexit` handler forks a sleeping child that inherits all exploit FDs. The shared file descriptions never reach zero references, so pipe destruction is deferred until reboot.
- **Ring disarm:** before exit, use the surviving virtual-write descriptor to set `pipe_buffer.ops = NULL` for every forged slot. `free_pipe_info()` skips slots without operations instead of calling a release callback.

Duplicating a forged slot with `tee()` is not a repair: it only moves the eventual invalid page put to the holder pipe. Keep the descriptor-holder fallback because a partial ring-disarm walk is itself firmware- and corruption-sensitive.<sup>[[2]](#references)</sup>

## Path-based privileged-exec restrictions

Some Android vendor controls kill UID-0 execution from writable paths while allowing trusted system paths. With `CAP_SYS_ADMIN`, a narrowly scoped bypass is to bind-mount the payload over a dormant trusted executable, execute the trusted pathname, and lazily detach the mount after daemonization. The A17 port shadows `/system/bin/lmkd`; this is preferable to overwriting a firmware-specific global DEFEX feature word because it avoids disabling enforcement system-wide.<sup>[[2]](#references)[[4]](#references)</sup>

```sh
if mount --bind "$A/g4d" /system/bin/lmkd 2>"$A/g4d.mnt"; then
/system/bin/lmkd >"$A/g4d.out" 2>&1
rc=$?
umount -l /system/bin/lmkd
else
"$A/g4d" >"$A/g4d.out" 2>&1
rc=$?
fi
echo "G4D-RC=$rc" >"$A/g4d.rc"
```

For a reusable root channel, an abstract Unix socket avoids filesystem socket cleanup, `SO_PEERCRED` can restrict clients to explicitly allowed UIDs, and a fresh PTY per connection preserves interactive shell semantics. This remains per-boot access unless a separate boot-persistent modification is made.<sup>[[2]](#references)[[3]](#references)</sup>

## Porting and test checklist

The public port's workflow is useful beyond this specific bug:<sup>[[2]](#references)[[3]](#references)</sup>

- Extract `boot.img` from the exact stock firmware and recover `vmlinux`/`Image` plus symbols and BTF.
- Audit every accessed member and symbol; refuse to run unless the runtime profile matches the expected build.
- Parameterize the physical kernel base instead of inheriting another device's value.
- Boot the real kernel and the same exploit binary in QEMU with an initramfs, applying only patches required for absent platform components.
- Automate success markers and poweroff, and test malformed fake objects, misaligned physical reads, forge-budget exhaustion, and pipe teardown before device deployment.
- Treat the race as probabilistic: preserve a healthy boot after ordinary failures and run bounded, observable retries instead of converting every miss into a reboot.

## References

- [1] [Nebula Security — IonStack Part 3: The First Public Android 17 Root](https://nebusec.ai/research/ionstack-part-3/)
- [2] [Mobile Hacking Lab — GhostLock: Root Shell on the Samsung Galaxy A17](https://mobilehackinglab.com/blog/cve-2026-43499-ghostlock-a17-root-shell)
- [3] [Mobile Hacking Lab — `ghostlock-a17` exploit and porting resources](https://github.com/mobilehackinglab/ghostlock-a17)
- [4] [Samsung Knox — Defeat Exploit (DEFEX)](https://docs.samsungknox.com/admin/fundamentals/whitepaper/samsung-knox-mobile-security/system-security/defeat-exploit/)

{{#include ../../banners/hacktricks-training.md}}
5 changes: 5 additions & 0 deletions src/mobile-pentesting/android-app-pentesting/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ Sometimes it is useful to **modify application code** to access **hidden informa
- [Play Integrity attestation spoofing (SafetyNet replacement)](play-integrity-attestation-bypass.md)<sup>[[1]](#references)</sup>
- [Android app-level virtualization / app cloning abuse & detection](android-application-level-virtualization.md)
- [Shizuku Privileged API (ADB-based non-root privileged access)](shizuku-privileged-api.md)

{{#ref}}
../../binary-exploitation/linux-kernel-exploitation/futex-pi-uaf-pipe-buffer-workqueue-usermodehelper.md
{{#endref}}

- [Exploiting Insecure In-App Update Mechanisms](insecure-in-app-update-rce.md)
- [Abusing Accessibility Services (Android RAT)](accessibility-services-abuse.md)
- [Android IME / InputMethodService Abuse (Malicious Keyboards)](inputmethodservice-ime-abuse.md)
Expand Down