Dirty Pipe

CVE-2022-0847

Theory

In March 2022, a researcher named Max Kellerman publicly disclosed a Linux Kernel vulnerability (nicknamed "Dirty Pipe" for its similarities to the notorious "Dirty Cow" exploit affecting older versions of the kernel) that allowed attackers to arbitrarily overwrite files on the operating system. Arbitrary file overwrites at the kernel level can be very easily leveraged to escalate privileges on the machine

The vulnerability arises because of how the kernel implements "pipes": the Linux kernel provides a system call called "splice()", which is effectively a shortcut designed to speed up the process of pushing the contents of a file into a pipe. This optimisation is achieved by moving references to the pages storing the file contents, rather than moving the entirety of the data. In other words, splice() allows us to point a pipe at a page which is already loaded into memory, containing a section of a file originally opened by a process requesting read-only access.

It's not quite that simple, however; we are still missing one final piece of the puzzle. Usually when you write to a pipe after splicing a file, a new pipe_buffer is created to avoid overwriting the spliced data. So, how do we force the kernel to allow us to overwrite the relevant page(s)?

This is the real crux of the vulnerability, and it can all be traced back to two commits in the Linux kernel:

  • A bug was introduced in Linux Kernel v4.9 (2016) which allowed pipes to be created with arbitrary flags. None of the flags available at the time were in any way dangerous, so this wasn't an issue, until...

  • Linux Kernel v5.8 (2020) added a new flag — PIPE_BUF_FLAG_CAN_MERGE. In simple terms, this flag tells the kernel that the page can be updated without forcing a rewrite of the data.

To summarise: we have a flag that allows us to tell the kernel that it's okay to overwrite the data in a page, we have a bug that allows us to specify arbitrary flags for a pipe, and we have a system call that inadvertently allows us to point pipes at page buffers which were opened as read-only. What could possibly go wrong?

Put simply, the exploit first opens a target file with the read-only flag set — in order to do this, we must choose a file that we have permission to read. The exploit then prepares a pipe in a special way, forcing the addition of the PIPE_BUF_FLAG_CAN_MERGE flag. Next, it uses splice() to make the pipe point at the desired section of the target file. Finally, it writes whatever arbitrary data that the user has specified into the pipe, overwriting the target page by merit of the PIPE_BUF_FLAG_CAN_MERGE flag.

Practice

The vulnerability has been patched in Linux kernel versions 5.16.11, 5.15.25 and 5.10.102, and Linux kernel versions newer than 5.8 are affected.

#Get Kernel version
$ uname -r
5.8.0-1035-aws

If you are not sure if a target system is vulnerable you may use this bash scripts developed by basharkey.

# Check for current kernel version
./dpipe.sh

# Check for specific kernel version
./dpipe.sh 5.10.11

Resources

Last updated