Hide Articles
 •   June 2, 2017  •   Security

Dirty COW (CVE-2016-5195) and the Facts

Hide Articles

On October 21st, 2016 the kernel which is used by millions of devices in the world faced a major bug which could cause the whole open source world foundation to cave in. It was the discovery of Dirty COW (Dirty copy-on-write) which had been a bug lurking in the famous Linux kernel since version 2.6.22 in 2007.

Dirty COW is a privilege escalation bug in the Linux kernel. Since the Linux kernel is used across many different devices and systems – including embedded, mobile (Android), virtualization and cloud platforms (Docker, AWS ), and IoT devices, the impact could be huge.

To understand how the flaw works, we first need to understand how the memory is handled by Linux kernel.

 

The logical memory consists of 4k blocks of contiguous memory locations called pages. These pages are mapped to physical memory pages by a translation table in the CPU.

Suppose there are two processes which read from the same physical memory location.

dcow1

 

As long as reading continues, the physical memory page will not alter. When one process tries to modify or write something to the physical memory, the kernel comes in action and makes a copy of the physical page and will give it to the process which is supposed to modify the page.

dcow2

So the modification will be on the copy of the memory page instead of the original page. This is called copy-on-write or COW. Remember, the sole responsibility of a kernel is to allocate memory for the processes so that they don’t interfere with each other. So far so good. But there is a race condition occurring when the kernel makes a copy of the original page and writes to it. A race condition occurs when two or more threads can access shared data and they try to change it at the same time.

Dirty COW exploits work by tricking the kernel into a race condition in the copy-on-write mechanism. To understand the exploit, you need a root owned file which has read access to unprivileged users. Now I will explain the important code portions of the exploit. The full formed code can be found here
map=mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,f,0);
mmap() creates a new mapping in the virtual address space of the calling process. mmap does not really copy the whole content of the file into memory, instead, it only maps the file onto the memory.
So what happens here is mmap maps the root file directly into the memory and you can read the content of the file or write to a copy of it. The changes to the copy of the file do not propagate to the real underlying file.
pthread_create(&pth1,NULL,madviseThread,argv[1]);
pthread_create(&pth2,NULL,procselfmemThread,argv[2]);
Now two threads of the same process will run in parallel.
c+=madvise(map,100,MADV_DONTNEED);
one is the madvise system call. madvise system call is used to tell the kernel how we intend to use a memory mapped area. the advice that we give to the kernel is MADV_DONTNEED which means that do not expect access in the near future and kernel can free the memory associated with it.
c+=write(f,str,strlen(str));
The other thread opens the file /proc/self/mem. As you probably know most of the resources in Linux are managed as the file, /proc/self/mem refers to file provided for the current process. The exploit will use this thread to write to the memory with the string that we passed as an argument. Remember we don’t modify the underlying file. If we run these two threads once or isolate them, nothing will be happened, because that is the expected outcome, but if we run these threads in the loop there might have chances of occurring a race condition and the exploit will work.
Now the word “Dirty” comes into play. A page of a memory is dirty if it is modified. Usually, before replacing a particular memory block, it is checked to see whether the block of memory is dirty and needs to write to disk. Since we passed madvise to the kernel the copy of the file will get tossed whether or not it is dirty. So whenever a write to copy of file occurs madvise system call will toss the file and will make sure that the copy of the file is not in any memory caches. This is the key to the exploit, since there is no copy of the file in the cache, every time a new copy of the file will be created and creating a copy of the file takes time.

That is, we write in the original underlying file before the page table entry gets updated to point to the copy of the file. A root owned file has been modified by an unprivileged user, can you believe it. This bug can endanger a web hosting company as a normal shell user can gain root privilege.
An Example of the exploit is given below,
Finding the kernel version
$ uname -r
4.5.2-040502-generic

The kernel version I am using has vulnerabilities.
Gaining the root access on Linux mint OS
$ sudo su -
[sudo] password for sanju:
sanju-Inspiron-3521 sanju # id
uid=0(root) gid=0(root) groups=0(root)
Since the uid is 0, so I have gained the root access.
Writing a line into the root owned file
# echo Only root can write in this file > sample.txt
Changing the permission of the file so that other’s can read the file.(This is important as root owned file can be writable using the exploit only if the file is readable for others)
# chmod 404 sample.txt
You can see the contents of the root owned file sample.txt
# cat sample.txt
Only root can write in this file

Now, log out as root and enter as a normal user
# exit
When a normal user tries to write to the root owned file, sample.txt. The result is obvious
$ echo I too want to write in this file >>sample.txt
bash: sample.txt: Permission denied

Till now we saw that a normal user can not write to a root owned file. Now lets do the magic!
Lets compile the exploit using gcc compiler
$ gcc dirtyc0w.c -pthread
Execute the compiled file as ./a.out and give arguments as target file and content to be added
$ ./a.out sample.txt “I have also written to this file ;)”
mmap 7f215b65d000
madvise 0
procselfmem -794967296

cat the contents of the file after the exploit has been executed
$ cat sample.txt
I have also written to this file

You have seen the maic, have not you? I just wrote something in the root owned file whicj is not less than a magic!
Now that you have seen the severity, It is important to patch the vulnerable kernels or update them. Different vendors have already rolled out patches at the dawn of discovery of the exploit. The patch is very simple it will ensure that copy-on-write is complete and only then allow writing to the underlying file.
Cloudlinux servers
——————
Cloudlinux has released latest patched kernels. You can update it using YUM.

Cloudlinux 7 – yum clean all; yum install kernel-3.10.0-427.10.1.lve1.4.22.el7 kmod-lve-1.4-22.el7 —enablerepo=cloudlinux-updates-testing

Cloudlinux 6 – yum clean all; yum install kernel-3.10.0-427.10.1.lve1.4.22.el7 kmod-lve-1.4-22.el7 —enablerepo=cloudlinux-updates-testing

Note: Reboot is required to take effect
The customers subscribed to cloud Linux kernel care can update their server without the reboot.
Redhat/Centos servers
———————
Redhat/Centos 5.x,6.x,7.x are all vulnerable to the exploit. So you either update your kernel or update the whole packages with YUM.
To update the kernel only run the following command,
yum update kernel
To update your whole packages with the kernel, run
yum update
Note: Reboot is required to take effect
Ubuntu/Debian servers
———————
If your server’s kernel version falls into one of the below-mentioned kernels, you are not vulnerable. Any other kernel versions not belonging to the below-mentioned kernel versions are vulnerable. You can check the kernel version using the command uname -a.

4.8.0-26.28 for Ubuntu 16.10
4.4.0-45.66 for Ubuntu 16.04 LTS
3.13.0-100.147 for Ubuntu 14.04 LTS
3.2.0-113.155 for Ubuntu 12.04 LTS
3.16.36-1+deb8u2 for Debian 8
3.2.82-1 for Debian 7
4.7.8-1 for Debian unstable

Since Ubuntu has released the fix of the bug, All users need to do is upgrade their system.
sudo apt-get update
sudo apt-get dist-upgrade

After rebooting check the kernel version and ensure the kernel version is resilient to the bug.

Make sure to update your Linux servers to stay protected.

About the Author:

Sanjay, an RHCE and CCNA certified Engineer is a tech enthusiast who is absorbed and attentive in tasks he is assigned to do. His jovial and energetic nature accentuates the good team player in him who is always ready to help. During his free time, he enjoys reading technical articles and keeping himself up-to-date on new technologies.

Leave a Reply

Your email address will not be published. Required fields are marked *

*