diff --git a/src/binary-exploitation/freebsd-ptrace-rfi-vm_map-prot_exec-bypass-ps5.md b/src/binary-exploitation/freebsd-ptrace-rfi-vm_map-prot_exec-bypass-ps5.md index 504e8d16e7e..08f8e723741 100644 --- a/src/binary-exploitation/freebsd-ptrace-rfi-vm_map-prot_exec-bypass-ps5.md +++ b/src/binary-exploitation/freebsd-ptrace-rfi-vm_map-prot_exec-bypass-ps5.md @@ -185,8 +185,60 @@ int main(){ - Utilities/vm_map helpers: https://github.com/buzzer-re/playstation_research_utils - Related projects: https://github.com/OpenOrbis/mira-project, https://github.com/ps5-payload-dev/gdbsrv +## Additional FreeBSD kernel exploitation audit patterns + +The PS5 technique above assumes you already have kernel R/W. Calif's 2026 FreeBSD audit released three useful **pre-R/W bug patterns** that are worth checking in native FreeBSD code paths as well: + +### 1. Copyin/copyout size confusion into a caller-owned stack buffer + +When a helper chooses between a small **on-stack array** and a heap allocation, verify that **both** the allocation size and the later `copyin`/`copyout` length use the **element size**, not the pointer size. In the released `setcred(2)` LPE, a helper handling supplementary groups used `sizeof(pointer)` instead of `sizeof(gid_t)`, so a user-controlled group count copied `N*8` bytes into a caller frame that only reserved space for `N*4`-sized entries. + +Things worth checking during audit/exploitation: + +- Stack/heap dual paths such as `smallbuf` vs `malloc()` fallbacks. +- Copies that start at an **interior pointer** like `buf + 1`; the bug may miss the saved return address but still smash nearby locals or callee-saved registers. +- Whether the **privilege check happens after the copy**, turning a nominally privileged API into a reachable pre-check overflow. +- Exact **version-specific frame layout**. The same source bug may exist on multiple FreeBSD releases while only one build is exploitable because the compiler output, local-variable ordering, or mitigation state changed. + +### 2. Redirected syscall numbers that are not re-validated before `sysent` lookup + +Audit every path that can **translate or redirect a syscall number** (`SYS_syscall`, `SYS___syscall`, ptrace remote syscall helpers, compat/emulation wrappers). The important rule is: **bounds-check the final syscall number after redirection**, not just the original request. + +If the redirected value reaches `sv->sv_table[sc]` unchecked, adjacent kernel memory may be interpreted as a fake `struct sysent`: + +- `sy_call` can become an unintended kernel call target. +- `sy_narg` can be turned into a later copyin/copyout overflow. +- `sy_flags` / tracing metadata can expose secondary side effects. + +Extra things to look for: + +- `register_t` → `int` truncation or signedness bugs that enable **negative indices** as well as oversized positive ones. +- A **safe native syscall path** elsewhere in the kernel that already performs the missing post-redirect check; diffing the safe and unsafe paths is often enough to spot the bug quickly. + +### 3. Embedded `selinfo` / poll waiter lifetime bugs that become linked-list writes + +Any kernel object embedding `struct selinfo` (or related `knlist` state) must **drain waiters before the object is freed**. A common review pattern is: + +- object is reachable from `poll(2)` / `select(2)` / `kqueue(2)` +- a wait path calls `selrecord()` +- the final free path destroys the lock/object **without** `seldrain()` + +That leaves stale waiter metadata pointing into freed memory. If the freed slot is reclaimed with attacker-influenced data (Calif used `SCM_RIGHTS`-driven `filedescent` allocations against `procdesc`), the later timeout/cleanup path may run a stale `TAILQ_REMOVE()` or similar unlink logic on the reclaimed object. + +Why this matters: + +- list removal mutates **forward and backward pointers**, so reclaimed wait state can become a practical **kernel pointer write** primitive +- the trigger may be delayed until **poll timeout**, **close**, or another async cleanup path, which helps reclaim the freed slot first +- `selwakeup()` on one code path is **not enough** if another free path can skip it; what matters is that every terminal lifetime path drains the waiters before `free()` + +A good FreeBSD-specific grep set is: `selrecord`, `seldrain`, `selwakeup`, `knlist_destroy`, `TAILQ_REMOVE`, and final free/destructor routines for objects reachable from `pdfork`, sockets, pipes, procdescs, and device file operations. + ## References +- [Calif - An AI audit of FreeBSD](https://blog.calif.io/p/an-ai-audit-of-freebsd) +- [Calif setcred write-up](https://github.com/califio/publications/blob/main/MADBugs/freebsd/setcred-CVE-2026-45250/WRITEUP.md) +- [Calif ptrace PT_SC_REMOTE write-up](https://github.com/califio/publications/blob/main/MADBugs/freebsd/ptrace-CVE-2026-45253/WRITEUP.md) +- [Calif procdesc/file write-up](https://github.com/califio/publications/blob/main/MADBugs/freebsd/file-CVE-2026-45251/WRITEUP.md) - [Usermode ELF injection on the PlayStation 5](https://reversing.codes/posts/PlayStation-5-ELF-Injection/) - [ps5-payload-dev/sdk](https://github.com/ps5-payload-dev/sdk) - [ps5-payload-dev/elfldr](https://github.com/ps5-payload-dev/elfldr)