Analysis of a public, patched, third-party CVE, written as a portfolio example. Not original discovery by Goldberg Security Research.
Summary
Dirty Pipe lets an unprivileged local user overwrite data in read-only files by
abusing how the kernel merges pipe buffers with the page cache. Because the write lands in the
page cache rather than going through the filesystem's permission checks, an attacker can clobber
files they can only read — including root-owned setuid binaries and
/etc/passwd — and pivot to root.
Root Cause
A struct pipe_buffer carries a flags field. The flag
PIPE_BUF_FLAG_CAN_MERGE tells the kernel a buffer's backing page may be appended to.
The bug: when a page-cache page was spliced into a pipe, the buffer's flags were
never initialised, so a stale CAN_MERGE flag could remain set:
// copy_page_to_iter_pipe() / push_pipe() set up a pipe_buffer
// referencing a page-cache page, but left buf->flags uninitialised.
struct pipe_buffer *buf = ...;
buf->page = page; // page-cache page backing a file
buf->offset = offset;
buf->len = len;
// buf->flags NOT cleared -> may still contain PIPE_BUF_FLAG_CAN_MERGE
A subsequent write() to the pipe sees CAN_MERGE and writes directly into
the existing page — which is the file's page-cache page. The page is marked dirty in memory but
the on-disk permission/ownership are never consulted.
Exploitation
The primitive is remarkably simple and reliable:
- Open a target read-only file (e.g. a setuid binary) and
splice()one byte from it into a pipe — priming a pipe buffer that references the file's page-cache page withCAN_MERGEset. write()attacker-controlled bytes to the pipe; they overwrite the file's page-cache contents at the chosen offset.- Any process reading the file now sees the modified bytes.
Practical constraints from the original disclosure:
- The attacker must have read permission on the file.
- The offset cannot be on a page boundary.
- The write cannot cross a page boundary.
- The file cannot be resized.
Classic escalations: patch /etc/passwd to remove root's password, or
overwrite the bytes of a setuid-root helper to run an attacker payload as root.
Impact
Reliable local privilege escalation with a tiny, deterministic exploit — no memory-corruption gymnastics, no KASLR concerns. Trivial to weaponise, which is why it spread widely.
Remediation
- Update to a fixed kernel (5.16.11 / 5.15.25 / 5.10.102 or later).
- No robust pre-patch mitigation exists beyond patching; minimise local untrusted access.
Timeline
- 2020 — Flaw introduced with a pipe-buffer refactor (kernel 5.8).
- 2022-02 — Reported to the kernel security team.
- 2022-03-07 — Public disclosure and coordinated patch.