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:
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=19be0eaffa3ac7d8eb6784ad9bdbc7d67ed8e619
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