dirtyfrag: Dirty Frag: How a Linux Fast Path Turned Read-Only Files into a Root Shell
A deterministic privilege-escalation framework that chains two kernel subsystems, writes through page cache pages, and shows how “dirty” bugs keep evolving.

Dirty Frag is a vulnerability (class) that achieves root privileges on most Linux distributions by chaining the xfrm-ESP Page-Cache Write vulnerability and the RxRPC Page-Cache Write vulnerability.
- Dirty Frag turns a Linux optimization story into a security story by showing how zero-copy networking and in-place crypto can turn read-only page-cache data into a write target.
- The exploit is compelling because it is deterministic, so the attack path is repeatable once the kernel conditions are in place.
- Its real novelty is the dual-path design, where xfrm-ESP and RxRPC reach the same primitive through different kernel features.
- Dirty Frag extends the Dirty Pipe lineage by moving the weak point from pipe buffers into socket and page-cache plumbing.
The Read-Only Lie
The unsettling part of Dirty Frag is not that it writes to memory. It is that it writes to memory that should have stayed read-only. A file like /usr/bin/su looks fixed on disk, but the kernel’s own fast paths can briefly treat a page from that file as something it can modify.
That is the whole article in one sentence. Dirty Frag is a privilege-escalation framework that chains two Linux kernel subsystems to turn page-cache data into a write primitive, then uses that primitive to alter a privileged binary and reach a root shell.
Why This Exploit Feels So Clean
A lot of kernel exploits depend on timing. Dirty Frag does not. That matters because the exploit is built around logic that the kernel follows consistently once the setup is correct, which makes the result easier to repeat and easier to reason about.

Because it is a deterministic logic bug that does not depend on a timing window, no race condition is required, the kernel does not panic when the exploit fails, and the success rate is very high.
// The exploit uses kernel primitives, not a timing race.
// setup_userns_netns();
// add_xfrm_sa();
// splice(file, pipe, socket);
// trigger page-cache write primitive;
if (success) {
// privileged binary is now altered in place
execve("/bin/sh", argv, envp);
}
Two Kernel Paths, One Write Primitive
Dirty Frag is broader than a single bug report. It chains two different kernel paths to reach the same outcome. One path uses xfrm-ESP and user namespaces. The other uses RxRPC and avoids that namespace dependency. The point is not that the two paths look the same. The point is that both can land on the same kind of page-cache write primitive.
| Exploit | Mechanism | Dependency shape | Reliability | What it teaches |
|---|---|---|---|---|
| Dirty Frag | Page-cache write primitive through xfrm-ESP or RxRPC | Two kernel paths, one of which can avoid namespace setup | Deterministic and very high | Fast paths can compose into a write primitive |
| Copy Fail | Page-cache write primitive through the crypto API and splice | Often leans on AF_ALG and user namespaces | Deterministic and high | Crypto plumbing can expose the same class of bug |
| Dirty Pipe | splice-based write into pipe buffers | Pipe-buffer manipulation | Deterministic and high | Zero-copy plumbing can rewrite read-only data |
| Dirty COW | COW race against memory protection | Race condition in copy-on-write | Timing dependent | A race is harder to trust than a logic flaw |
How exp.c Stages the Attack
The code is deliberately compact. That compactness hides a lot of kernel knowledge. The exploit sets up namespaces when needed, configures the network state it wants, and uses splice() to keep the page pinned as it moves through kernel buffers instead of being copied in the normal way.
That detail matters because the exploit is not trying to overwrite a file through a normal write syscall. It is trying to make the kernel reuse the same physical page in a context where an in-place operation becomes a file modification. The tiny embedded payload then turns the altered file into a root shell.
// conceptually simplified flow
unshare(CLONE_NEWUSER | CLONE_NEWNET);
setup_kernel_state();
splice(fd_file, NULL, fd_pipe, NULL, len, 0);
move_page_into_socket_state();
trigger_in_place_processing();
// page cache page now contains attacker-controlled bytes
Dirty Frag Is the Next Step After Dirty Pipe
The family resemblance is real. Dirty Pipe made the page cache writable through pipe buffers. Dirty Frag keeps the same editorial tension, but moves the weak point into socket fragments and related networking machinery. That is why it feels less like a one-off exploit and more like an evolution of a bug class.
| Project | Core target | Main primitive | Nature of bug | Why it matters |
|---|---|---|---|---|
| Dirty COW | Memory protection and COW | Race on copy-on-write | Timing race | Shows how fragile COW assumptions can be |
| Dirty Pipe | Pipe buffers | splice-driven page-cache write | Deterministic logic flaw | Turned read-only pages into write targets |
| Copy Fail | Crypto and page-cache plumbing | In-place crypto write path | Deterministic logic flaw | Extended the page-cache write idea into crypto APIs |
| Dirty Frag | xfrm-ESP and RxRPC | Dual path page-cache write primitive | Deterministic logic flaw | Shows how multiple networking subsystems can converge on the same write |
Why the Disclosure Mattered
The repo is also a disclosure story. The embargo broke early, which forced the researcher to publish before the clean version of the rollout existed. That created urgency for distros, defenders, and anyone responsible for hardening Linux fleets.

Copy Fail was the motivation for starting this research.
That matters because this is not just a proof-of-concept for curiosity’s sake. It is a reference point for defenders, a test case for mitigations, and a reminder that kernel attack surfaces do not stay isolated when subsystems are composed for performance.
What the Repo Says About Modern Kernel Security
Dirty Frag is really a lesson about composition. A file page, a socket fragment, in-place crypto, and zero-copy networking are all sensible optimizations on their own. Put them together, and the safety assumptions begin to leak.
That is why the repo matters beyond the headline. It shows that “read-only” is not a property you can trust if the kernel can be convinced to keep the same page alive across multiple fast paths. The code is small, but the implication is large.