Table of Contents
Since March 7, the bug with code CVE-2022-0847, also named Dirty Pipe, has been publicly disclosed. This vulnerability initially affects the Linux kernel from version 5.8 onwards and allows privilege escalation by writing to read-only locked files. Many systems, including the latest versions of Android and some distributions such as Ubuntu, Debian or Fedora are affected.
Before explaining the details of the vulnerability, it is useful to review some theoretical concepts of operating systems and Linux in particular:
- Memory pages. Smallest data unit for memory management in a virtual memory based operating system. Its minimum size is 4Kb.
- Cached pages. These are memory pages that have been recently accessed and are stored in an intermediate faster memory in order to speed up subsequent accesses.
- Pipes. For inter-process communications, shared memory pages are often used, where one process reads and another writes. Typically, a pipe spans multiple memory pages. They are the same as those used for concatenating commands in the terminal, using the “|” character.
- Anonymous pipes. When the information shared between processes does not occupy an entire memory page, it can be reused for another pipe, resulting in data from different pipes coexisting in the same memory page.
- Pipe flags. Pipe flags specify characteristics such as status and permissions. It is in one of these flags, PIPE_BUF_FLAG_CAN_MERGE, where the problem arises.
The PIPE_BUF_FLAG_CAN_MERGE flag was introduced in kernel 5.8, in a commit (f6dd975583bd8ce088400648fd9819e4691c8958) released in May 2020. Its function is to indicate that the data in a pipe of a page can be merged without the need to rewrite the data in memory.
The real problem was given by the commit (241699cd72a8489c9446ae3910ddd243e9b9061b) published in October 2016. At that time, functions were defined to reserve the memory of the pipes, but without initializing the variable where the flags are stored. At that time, the available flags were not very interesting, so it did not pose a risk.
But since this new flag was defined, the lack of initialization did result in a problem. Since the kernel always has the cached pages under its control, it does not check its permissions when using a page.
Dirty Pipe vulnerability CVE-2022-0847 exploit
The discoverer of the bug, Max Kellermann, also developed an exploit for this problem which is available on his website about Dirty Pipe vulnerability. Basically, it works as follows:
- It starts by opening a file in read mode, which can later be written to, even if the program does not have write permissions.
- It creates a pipe with the pipe() system call. This function gives the same process access to the descriptors that allow writing and reading.
- Writes any type of information into the pipe to fill it completely and have the memory pages flagged with the PIPE_BUF_FLAG_CAN_MERGE flag.
- Once all the pages have been marked, it allows the kernel to free them by reading all the data from the pipe that it had written.
- From this point on, when the kernel reserves memory pages making use of the functions introduced in 2016, it will not initialize their flags and they will be marked with the PIPE_BUF_FLAG_CAN_MERGE flag.
- It uses the splice() function to load the file that had been opened at the beginning. The memory page allocated to this file will be the same as that of our empty pipe, because it was marked with the flag.
- It directly overwrites the data in the pipe.
This exploit can be used to elevate privileges on a system by overwriting the contents of /etc/passwd, an example exploit is detailed below:
- Check the first line of the /etc/passwd file, confirming that the root user is password protected.
- Confirm that, when executing the su command, authentication is requested.
- Compile the exploit programmed by Max Kellermann and save it under the name “exploit”.
- Run the exploit overwriting from byte 4 and removing the x that protects the root user with the password.
- When executing the su command, as the /etc/passwd file is modified, it does not ask for the password.
- Modify the file to return it to its original state.
The only possible mitigation is using a Kernel that initialize flag values or use one that does not implement de affected flag. Due to this situation is mandatory to upgrade the kernel of affected systems in order to correct the Dirty Pipe vulnerability.
Most of the Linux distributions that make use of kernels affected by this vulnerability have already published updates to solve the problem.
In the case of Android, as of March 17, there are still no references to this bug in its security bulletins, so the affected systems do not have possible mitigation at the moment. Only some versions of Android 12 use the 5.10 kernel, so not all devices with this version of Android are affected.
Other distributions, such as RedHat o SuSE, have published patches even for kernels that are not affected by this vulnerability, such as RedHat 8, which uses the 4.18 kernel. In this case they patch 2016 bug, to ensure that the memory pages are initialized correctly, setting the values of the flags. The bug fixed by this patch would affect Linux versions later than 4.9:
Thus, although the PIPE_BUF_FLAG_CAN_MERGE flag does not exist in these versions, the rest of the flags will also be initialized correctly. The existing flags for the memory pages are defined in the include /linux/pipe_fs_i.h file.
The patch released by RedHat and Suse addresses the vulnerability by fixing the bug of the 2016 commit. This patch fixes the source of the problem by initializing flags making it impossible for future exploits to make use of flags that were already defined in previous kernel versions.
References about Dirty Pipe vulnerability CVE-2022-0847
- Author – https://dirtypipe.cm4all.com/
- Patch – https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/lib/iov_iter.c?id=9d2231c5d74e13b2a0546fee6737ee4446017903
Advisories for Linux distributions
Discover our work and cybersecurity services.