DF-2912 / dl64_tiny.c
/* DF-2912: l64_makevirginlabel unsigned underflow on tiny slices. * * vn disk with a 1-sector MBR slice -> d_total_size (512) < ressize * (4096) -> d_abase = d_total_size - ressize underflows to ~2^64. * * expect (vulnerable): d_abase = 0xfffffffffffffe00 (512-4096 wrapped) * expect (patched): d_abase sane (clamped, no wrap) */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <sys/ioctl.h> #include <sys/disklabel64.h> #include <sys/types.h> static void putle32(uint8_t *p, uint32_t v) { p[0]=v;p[1]=v>>8;p[2]=v>>16;p[3]=v>>24; } int main(int argc, char **argv) { const char *dev = argc > 1 ? argv[1] : "/dev/vn0s1"; struct disklabel64 dl; uint8_t img[63 * 512]; uint8_t *mbr; int fd, rv; /* build a 31.5KB disk with a 1-sector slice at LBA 16 */ memset(img, 0, sizeof(img)); mbr = img; mbr[0x1be + 0] = 0x80; /* bootable */ mbr[0x1be + 4] = 0xA5; /* DFly slice type */ putle32(mbr + 0x1be + 8, 16); /* start LBA 16 */ putle32(mbr + 0x1be + 12, 1); /* size: 1 sector */ mbr[0x1FE] = 0x55; mbr[0x1FF] = 0xAA; { FILE *f = fopen("/tmp/df2912.img", "w"); fwrite(img, 1, sizeof(img), f); fclose(f); } { char cmd[256]; snprintf(cmd, sizeof(cmd), "vnconfig -c vn0 %s 2>/dev/null", "/tmp/df2912.img"); if (system(cmd) != 0) printf("DF2912 vnconfig attach rc!=0\n"); sleep(1); } fd = open(dev, O_RDONLY); if (fd < 0) { printf("DF2912 open %s errno=%d (%s)\n", dev, errno, strerror(errno)); return 1; } rv = ioctl(fd, DIOCGDVIRGIN64, &dl); if (rv < 0) { printf("DF2912 DIOCGDVIRGIN64 rv=%d errno=%d (%s)\n", rv, errno, strerror(errno)); return 1; } printf("DF2912 d_total_size = %llu (512 expected)\n", (unsigned long long)dl.d_total_size); printf("DF2912 d_abase = 0x%016llx " "(underflow shows 0xfffffffffffffe00)\n", (unsigned long long)dl.d_abase); printf("DF2912 d_pbase = 0x%016llx\n", (unsigned long long)dl.d_pbase); printf("DF2912 d_pstop = 0x%016llx\n", (unsigned long long)dl.d_pstop); close(fd); system("vnconfig -u vn0 2>/dev/null"); return 0; } |