The “Dirty COW” vulnerability (CVE-2016–5195) discovered last year in Linux was incompletely patched, Bindecy researchers say.
The vulnerability was found to be caused by a race condition in the way the Linux kernel’s memory subsystem handles copy-on-write (COW) breakage of private read-only memory mappings. Discovered by Phil Oester, the bug could allow an unprivileged local attacker to escalate their privileges on a targeted system.
The vulnerability was found to impact Android as well, and could even escape containers. Soon after Google released a patch for the vulnerability, however, new attacks exploiting Dirty COW on Android were devised.
The most recent malware family to exploit the issue was observed in September of this year.
Although Dirty COW was one of the most hyped and branded vulnerabilities published, with every Linux version from the last decade affected, including Android, being vulnerable, the patch released for it stirred far little interest, Bindecy says. Because of that, over a year has passed since the patch was released, and no one noticed it was incomplete.
The original vulnerability impacted the get_user_pages function, which is used to get the physical pages behind virtual addresses in user processes. Basically, the bug would allow writing to the read-only privileged version of a page.
The fix for the vulnerability doesn’t reduce the requested permissions. Instead, “get_user_pages now remembers the fact the we went through a COW cycle,” the researchers explain.
Thus, on the next iteration, a read-only page is provided for a write operation only if FOLL_FORCE and FOLL_COW flags are specified, and the PTE is marked as dirty.
The problem, the security researchers say, is that the patch “assumes that the read-only privileged copy of a page will never have a PTE pointing to it with the dirty bit on.”
Bindecy discovered that the vulnerability can still be reproduced when Transparent Huge Pages (THP) and Page Medium Directory (PMD – one level above the PTE level), are involved.
While Linux usually uses 4096-bytes long pages, THPs can be even 2MB long, although they can be split into normal pages. Usually, the default THP support is for anonymous mapping only, but can be turned on or off while the system is running.
THP is implemented by turning on the _PAGE_PSE bit of the PMD, which results in PMD pointing to a 2MB physical page instead of a directory of PTEs.
What the researchers discovered was that Dirty COW patch code that deals with THP contains a function called can_follow_write_pmd that basically applies the same logic of can_follow_write_pte to huge PMDs.
According to the researchers, however, the issue is that, when it comes to huge PMD, “a page can be marked dirty without going through a COW cycle, using the touch_pmd function.” Each time get_user_pages tries to get a huge page, a called function results in the page being marked dirty without going through a COW cycle. Thus, can_follow_write_pmd’s logic is broken, the researchers say.
“At this point, exploiting the bug is straightforward — we can use a similar pattern of the original Dirty COW race. This time, after we get rid of the copied version of the page, we have to fault the original page twice — first to make it present, and then to turn on the dirty bit,” Bindecy notes.
The security researchers revealed information on a couple of exploit scenarios and also published a proof-of-concept to demonstrate the exploit. They reported the vulnerability (which was assigned CVE-2017–1000405) to the kernel and distros mailing lists last week and a patch was already committed to mainline kernel.
“This bug demonstrates the importance of patch auditing in the security development life-cycle. As the Dirty COW case and other past cases show, even hyped vulnerabilities may get incomplete patches. The situation is not reserved for closed source software only; open source software suffers just as much,” the researchers conclude.