FreeBSD OSS /dev/dsp Stale Kernel-Stack Buffer Local Privilege Escalation (CVE-2026-49417)
by Yayoi-cs · 2026-07-05
- Severity
- High
- CVE
- CVE-2026-49417
- Category
- binary
- Affected product
- FreeBSD kernel — OSS audio driver (/dev/dsp) buffer allocation / thread-stack recycling
- Affected versions
- Not specified in source (no README/advisory shipped with the PoC; repo name marks it a "1-day" exploit)
- Disclosed
- 2026-07-05
- Patch status
- unpatched
Tags
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-05 |
| Last Updated | 2026-07 |
| Author / Researcher | Yayoi-cs |
| CVE / Advisory | CVE-2026-49417 |
| Category | binary |
| Severity | High |
| CVSS Score | Not specified in source |
| Status | PoC |
| Tags | freebsd, kernel, oss, dev-dsp, kernel-stack-leak, rop, smep-bypass, cr4, local-privilege-escalation, c |
| Related | N/A |
Affected Target
| Field | Value |
|---|---|
| Software / System | FreeBSD kernel — OSS audio driver (/dev/dsp) buffer allocation / thread-stack recycling |
| Versions Affected | Not specified in source (no README/advisory shipped with the PoC; repo name marks it a “1-day” exploit) |
| Language / Platform | C, native FreeBSD kernel exploit (raw syscall instructions, kldstat/kldsym, pthread) |
| Authentication Required | Local-only |
| Network Access Required | No |
Summary
exp.c is a local FreeBSD kernel privilege-escalation exploit built around /dev/dsp (the OSS sound driver). It sprays hundreds of pthreads that call nanosleep() with distinctively tagged tv_nsec values so their kernel stacks/return addresses are recognizable, then repeatedly mmaps and releases /dev/dsp DMA buffers, scanning the mapped memory for pages that contain both the tagged marker value and kernel .text pointers — evidence that a released kernel thread-stack region has been recycled into a buffer the exploit can read and write from userland. Once it locates the stashed sys_nanosleep return address inside such a page, it overwrites that in-memory slot with a small ROP chain (disable SMEP by clearing the corresponding %cr4 bit, then jump to injected shellcode). When the targeted kernel thread returns, it executes the ROP chain and shellcode, which zeroes out the current thread’s credential structure (p_ucred) to grant root, then hands control back to spawn a root /bin/sh.
Vulnerability Details
Root Cause
The PoC’s behavior indicates that /dev/dsp buffer pages can be recycled from (or made to alias) kernel thread stack memory without being properly cleared/isolated between uses. This lets an unprivileged process both read stale kernel stack contents (including code return addresses and thread-identifying data) through an mmap’d DSP buffer, and — because that memory is later reused as an active kernel thread’s stack — write attacker-controlled values into a live return-address slot on that stack.
Attack Vector
- Resolve the running kernel’s base address and the
sys_nanosleepsymbol via the unprivilegedkldstat(2)/kldsym(2)interfaces, and compute offsets for apop %rax; retgadget, amov %rax,%cr4; retgadget, and axor %eax,%eax; retgadget from a statically-assumed kernel layout. - Spawn ~1200 pthreads that call
nanosleep()with atv_nsecvalue derived from each thread’s kernel thread ID (thr_self), so each thread’s kernel stack carries an identifiable marker while it sleeps. - Repeatedly
mmap()and hold, then release, 512/dev/dspDMA buffers (after configuring fragment size viaSNDCTL_DSP_SETFRAGMENT), pre-filling them with a recognizable pattern. - Scan the mmap’d buffer pages for ones containing both a sleeping thread’s marker value and pointers that fall inside the kernel’s
.textrange — identifying a page that now aliases (or was recycled from) that thread’s kernel stack, and locating the storedsys_nanosleepreturn address within it. - Overwrite that in-buffer return-address slot with a ROP chain: pop the original
%cr4value with SMEP cleared into%rax, executemov %rax,%cr4to disable SMEP, then jump into a userland shellcode page. - The shellcode (running with kernel privileges after the hijacked return) reads the current thread via
%gs-relative offsets, walks totd_proc -> p_ucred, and zeroes the credential fields (uid/gids/ngroups) to grant root, restores the stack pointer, and returns execution normally. - Poll
geteuid()from userland; once it reports0,execv("/bin/sh")to obtain a root shell.
Impact
An unprivileged local user can gain full root privileges on an affected FreeBSD system by exploiting the OSS /dev/dsp driver’s buffer/stack-recycling behavior — full local privilege escalation.
Environment / Lab Setup
Target: FreeBSD system exposing /dev/dsp (OSS audio driver) to unprivileged users, vulnerable kernel version
Attacker: Unprivileged local shell on the same host with a C compiler to build exp.c
Proof of Concept
PoC Script
See
exp.cin this folder.
| |
The exploit prints resolved kernel base/symbol addresses and gadget locations, sprays kernel stacks and DSP buffer allocations searching for an aliased page holding a sys_nanosleep return address, overwrites it with a SMEP-disabling ROP chain plus shellcode, and polls until the effective UID becomes 0, at which point it execs a root /bin/sh.
Detection & Indicators of Compromise
Signs of compromise:
- A previously unprivileged process obtaining
euid=0without going through a setuid binary or sudo/su - Heavy
/dev/dspopen/mmap/close churn combined with high pthread counts from a single non-audio process - Root shell (
/bin/sh) spawned as a direct child of a custom/unsigned binary shortly after such activity
Remediation
| Action | Detail |
|---|---|
| Primary fix | No vendor patch confirmed in source — the OSS driver must ensure /dev/dsp buffer memory is never aliased with or recycled from kernel thread stack memory without proper isolation/clearing, and kernel stack memory should not be user-mmap’able in any form |
| Interim mitigation | Restrict access to /dev/dsp to trusted users/groups only (device permissions), disable unused OSS/sound subsystems on multi-user or security-sensitive FreeBSD systems until patched |
References
Notes
Mirrored from https://github.com/Yayoi-cs/CVE-2026-49417_1day_LPE_exploit on 2026-07-05. The upstream repository ships no README/advisory (404); this description is derived from reading exp.c directly.
| |