简单吐槽一下dirtyCow
本来是来论坛看看有没有分享相关内容的,结果只看到了一个测试poc的帖子~~
来简单说说本人的分析。
这个漏洞涉及到的内核代码很复杂,如果没有相关基础的童鞋,建议还是放弃分析吧。
我是按照 https://github.com/dirtycow/dirtycow.github.io/wiki/VulnerabilityDetails 上的介绍,把相关流程看了一遍。简单介绍一下漏洞的触发流程。
1. 要写入的文件f必须可读,这样才能以read only模式打开文件f,并映射到内存空间
2. 把read only模式打开的文件映射到内存空间之后,以read write方式打开/proc/self/mem,这个文件就是本进程的内存,所以打开的mem是可写的。
3. 写mem,由于文件f是只读的,所以会触发Copy-On-Write,复制一份内存,复制完了之后,系统会认为新复制的内存页完全属于该进程,所以可以写。这时候会触发罪魁祸首的一段一代
1883 /* 1884 * The VM_FAULT_WRITE bit tells us that 1885 * do_wp_page has broken COW when necessary, 1886 * even if maybe_mkwrite decided not to set 1887 * pte_write. We can thus safely do subsequent 1888 * page lookups as if they were reads. But only 1889 * do so when looping for pte_write is futile: 1890 * in some cases userspace may also be wanting 1891 * to write to the gotten user page, which a 1892 * read fault here might prevent (a readonly 1893 * page might get reCOWed by userspace write). 1894 */ 1895 if ((ret & VM_FAULT_WRITE) && 1896 !(vma->vm_flags & VM_WRITE)) 1897 foll_flags &= ~FOLL_WRITE; 1898 1899 cond_resched();
也就是把foll_flags里面的FOLL_WRITE标志去掉了。这个标志用来标识是否验证可写。
紧接着cond_resched()进行系统调度~如果在这个时候调用 madvise(map,100,MADV_DONTNEED);~~~
4. 调用madvise告诉系统,map的那一块内存不再需要了,可以进行释放。随后系统释放掉新复制出来的,完全属于本进程的内存。
5. 这时候重新回到COW线程,cond_resched()后继续之行。重新获取page,发现没有,因为已经被释放了。这时候会重新走原来的流程,应该进行COW的,因为原来有FOLL_WRITE标志,需要验证是否可写,不可写的话进行复制。但是在之前的操作过程中,已经去掉了FOLL_WRITE标志。系统就认为是以只读的形式获取page的,因为只读,所以不会COW,就直接把原始的映射着文件f的内存页(page)作为了get_user_pages函数的返回值。
6. get_user_pages是在write里面调用的,write获取了get_user_pages返回的页,直接进行写操作。所以就把原始的映射着文件f的内存写了。
漏洞大意就是如此。有描述不准确和模糊的地方莫要较真。随着漏洞的曝光,我会再看情况适当补充其他细节~
PS1:先说说root,这个漏洞要root,最直接的办法就是写带set-user-id标志位的文件,例如ubuntu上的/bin/ping文件
qever@Q-Lab:/bin$ ls -la | grep ping -rwsr-xr-x 1 root root 44168 8 2014 ping -rwsr-xr-x 1 root root 44680 8 2014 ping6
至于Android上的root,至少我还没发现合适的方案~
PS2: 有兴趣的可以仔细看看下面这段万恶的while循环
http://androidxref.com/kernel_3.14/xref/mm/memory.c#1807
