Dirty COW (CVE-2016-5195): Recompile Linux Kernel 4.2 with the Fix Applied

Dirty COW (CVE-2016-5195) is a privilege escalation vulnerability in the Linux kernel.

The Problem

My laptop runs Debian Jessie with a custom 4.2 kernel, which isn’t maintained by Debian.

The kernel is vulnerable to the publicly available exploit:

$ ./dirtyc0w foo m00000000000000000
mmap 7f83599c6000

madvise 0

procselfmem 1800000000
$ cat foo 
m00000000000000000

How to Fix?

We can recompile the kernel with the fix applied.

Apply Fixes to the Kernel Source

The fix is available here.

Navigate to the kernel source directory /usr/src/linux-4.2.6/.

Apply the following fix (the line in green has to be added) to the file include/linux/mm.h:

#define FOLL_REMOTE 0x2000 /* we are working on non-current tsk/mm */
#define FOLL_COW 0x4000 /* internal GUP flag */

Verify:

$ grep -n FOLL_COW include/linux/mm.h
2095:#define FOLL_COW 0x4000 /* internal GUP flag */

Apply the following fixes to the file mm/gup.c. All lines in green need to be added, all lines in red must be removed or commented out.

}
// around line #35 in mm/gup.c
static inline bool can_follow_write_pte(pte_t pte, unsigned int flags)
{
        return pte_write(pte) ||
                ((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte));
}

static struct page *follow_page_pte(struct vm_area_struct *vma,
                unsigned long address, pmd_t *pmd, unsigned int flags)
// around line #75 in mm/gup.c
}
if ((flags & FOLL_NUMA) && pte_protnone(pte))
	goto no_page;
// if ((flags & FOLL_WRITE) && !pte_write(pte)) {
if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags)) {
	pte_unmap_unlock(ptep, ptl);
	return NULL;
}
// around line #324 in mm/gup.c
if ((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE))
//	*flags &= ~FOLL_WRITE;
        *flags |= FOLL_COW;
return 0;

Verify:

$ grep -n can_follow_write_pte mm/gup.c
35:static inline bool can_follow_write_pte(pte_t pte, unsigned int flags)
75: if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags)) {
$ grep -n "= FOLL_COW" mm/gup.c
324: *flags |= FOLL_COW;

Recompile the Kernel

It should go without saying, ensure that you have a backup of the working kernel before installing the new one.

# make -j3
# make modules_install install

Reboot.

$ uname -rv
4.2.6-dev #4 SMP Sat Oct 29 10:52:26 BST 2016

The kernel shouldn’t be vulnerable anymore:

$ ./dirtyc0w foo m00000000000000000
mmap 7f23f122f000

madvise 0

procselfmem 1800000000
$ cat foo 
this is not a test

Leave a Reply

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