DF-3053 / df3053.c
/* DF-3053 - nfsm_mbuftouio ignores copyout fault. * usage: df3053 <file-on-nfs> * thread A: read(fd, mapped, 4096); thread B: after 300ms mprotect(PROT_NONE). * BUG: read returns 4096 (success) while the mapping still holds 0x5A. * CORRECT: read returns -1/EFAULT. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <pthread.h> #include <sys/mman.h> static char *region; static volatile int started=0; static void *unmapper(void *a){ long ms=0; while(!started && ms<5000){usleep(1000);ms++;} usleep(300000); /* read() is now blocked on the RPC */ mprotect(region, 8192, PROT_NONE); printf("B: mprotect(PROT_NONE) done at t=300ms\n"); return NULL; } int main(int argc,char**argv){ pthread_t t; int fd; ssize_t r; pthread_mutex_t m=PTHREAD_MUTEX_INITIALIZER;(void)m; if(argc<2){fprintf(stderr,"usage: df3053 file\n");return 2;} fd=open(argv[1],O_RDONLY); if(fd<0){perror("open");return 1;} region=mmap(NULL,8192,PROT_READ|PROT_WRITE,MAP_ANON|MAP_PRIVATE,-1,0); if(region==MAP_FAILED){perror("mmap");return 1;} memset(region,0x5A,8192); pthread_create(&t,NULL,unmapper,NULL); started=1; errno=0; r=read(fd,region,4096); int e=errno; pthread_join(t,NULL); /* re-allow reading to inspect contents */ mprotect(region,8192,PROT_READ); int stale=1; for(int i=0;i<4096;i++) if(((unsigned char*)region)[i]!=0x5A){stale=0;break;} printf("A: read() ret=%zd errno=%d (%s)\n",r,e,e?strerror(e):"-"); printf("RESULT: %s (buffer %s 0x5A-stale)\n", (r==4096&&stale)?"BUG_REPRODUCED_full_success_stale_data": (r==4096&&!stale)?"PARTIAL_data_delivered": "CORRECT_fault_reported", stale?"still":"modified"); return 0; } |