DF-0919 / patch_frag.c
/* * patch_frag.c - patch fs->fs_frag in an FFS image to an out-of-{1,2,4,8} * value, to reproduce DF-0919 (kernel panic in ffs_isblock/ffs_clrblock/ * ffs_setblock/ffs_isfree_block, or OOB in ffs_fragacct). * * Build against the tree's own fs.h: * cc -I<repo>/sys -o patch_frag patch_frag.c * Use: * ./patch_frag <image> <new_frag> * * The kernel's superblock lives at SBOFF = 8192 (BBSIZE). We locate the * fs_frag field by offsetof() against <ufs/fs.h> so this tool stays correct * if the struct layout ever changes. */ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/param.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/mman.h> #include <stddef.h> #if defined(__DragonFly__) # include <vfs/ufs/ufs_types.h> # include <vfs/ufs/fs.h> #else # include <ufs/fs.h> #endif #ifndef SBOFF # define SBOFF BBSIZE #endif int main(int argc, char **argv) { const char *path; int fd, newfrag; struct stat st; char *m; int32_t *fragp; if (argc != 3) { fprintf(stderr, "usage: %s <image> <new_frag>\n", argv[0]); return 2; } path = argv[1]; newfrag = atoi(argv[2]); fd = open(path, O_RDWR); if (fd < 0) { perror("open"); return 1; } if (fstat(fd, &st) < 0) { perror("fstat"); return 1; } if (st.st_size < SBOFF + (off_t)sizeof(struct fs)) { fprintf(stderr, "image too small\n"); return 1; } m = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (m == MAP_FAILED) { perror("mmap"); return 1; } fragp = (int32_t *)(m + SBOFF + offsetof(struct fs, fs_frag)); printf("old fs_frag = %d\n", *fragp); *fragp = newfrag; printf("new fs_frag = %d\n", *fragp); if (msync(m, st.st_size, MS_SYNC) < 0) { perror("msync"); return 1; } munmap(m, st.st_size); close(fd); return 0; } |