DF-5326 / mp_bootaddr_underflow.c
/* * DF-5326 โ standalone arithmetic reproducer for the mp_bootaddress() * integer underflow in sys/platform/pc64/x86_64/mp_machdep.c:206-219. * * The logic below is copied verbatim from the DragonFly kernel source, * preserving the kernel's 32-bit unsigned (u_int) wrap-around semantics. * * bootMP_size uses the REAL value from the audited guest kernel * (X86_64_GENERIC, DragonFly 6.5-DEVELOPMENT): * ffffffff8113b8c0 D mptramp_start * ffffffff8113b96a D mptramp_end * bootMP_size = 0xAA = 170 bytes * * The returned value is stored by init386() straight into the kernel's * physical memory map: sys/platform/pc64/x86_64/machdep.c:2270-2272 * base_memory = physmap[1] / 1024; * physmap[1] = mp_bootaddress(base_memory); * so a wrapped return makes the kernel believe the first usable RAM region * is [0, ~0xFFFFC000) โ i.e. ~4GB of low memory including all MMIO/ROM * holes โ corrupting the physmem map for the whole boot. * * Build: cc -O2 -o mp_bootaddr_underflow mp_bootaddr_underflow.c * Run: ./mp_bootaddr_underflow */ #include <stdio.h> #include <stdint.h> typedef uint32_t u_int; /* kernel u_int is 32-bit on pc64 */ #define PAGE_SIZE 4096u #define PAGE_MASK (PAGE_SIZE - 1) #define trunc_page(x) ((x) & ~PAGE_MASK) /* real symbols from the guest kernel (nm /boot/kernel/kernel) */ #define MPTRAMP_START 0xffffffff8113b8c0ull #define MPTRAMP_END 0xffffffff8113b96aull static u_int bootMP_size, boot_address, mptramp_pagetables; /* verbatim mp_machdep.c:206-219 */ static u_int mp_bootaddress(u_int basemem) { bootMP_size = (u_int)(MPTRAMP_END - MPTRAMP_START); boot_address = trunc_page(basemem * 1024); /* round down to 4k boundary */ if (((basemem * 1024) - boot_address) < bootMP_size) boot_address -= PAGE_SIZE; /* not enough, lower by 4k */ /* 3 levels of page table pages */ mptramp_pagetables = boot_address - (PAGE_SIZE * 3); return mptramp_pagetables; } int main(void) { /* basemem in KB: degenerate first-usable-region ends, plus a sane BIOS */ u_int basemems[] = { 0, 1, 2, 4, 8, 9, 12, 13, 14, 15, 16, 17, 32, 638 }; unsigned i; bootMP_size = (u_int)(MPTRAMP_END - MPTRAMP_START); printf("bootMP_size = %u (0x%x) bytes [from mptramp_end-mptramp_start]\n", bootMP_size, bootMP_size); puts("basemem(KB) boot_address mptramp_pagetables effect on physmap[1]"); puts("----------- ------------ ------------------ --------------------"); for (i = 0; i < sizeof(basemems) / sizeof(basemems[0]); i++) { u_int b = basemems[i]; u_int r = mp_bootaddress(b); printf("%10u 0x%08x 0x%08x %s\n", b, boot_address, r, r >= 0x80000000u ? "WRAPPED: physmap[1] ~= 4GB -> whole low 4GB marked RAM" : (r == 0 ? "ZERO: trampoline PTs smash IVT/BDA at PA 0" : "sane")); } return 0; } |