DF-5340 / basemem_scan_underflow.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | /* * DF-5340 — (base_memory - 1) * 1024 underflow in mptable_search() * (mptable.c:284), the mptable.c sibling of the DF-5326 mp_bootaddress * class. * * base_memory (u_int, KB) = physmap[1]/1024 (machdep.c:2270), straight * from the loader-supplied SMAP/EFI memory map with no lower bound. * When the EBDA pointer (BDA 0x40e, machdep.c:2275-2276) is 0, the * "last 1K of base memory" scan target is computed as * * target = (u_int32_t)((base_memory - 1) * 1024); mptable.c:284 * * base_memory == 1 -> target == 0 -> KKASSERT(target != 0) * (mptable.c:368) PANIC * base_memory == 0 -> target == 0xFFFFFC00 -> pmap_mapdev() maps * the top-of-4GB MMIO hole (pa+0x400 crosses * the 4GB wrap) and scans garbage; the * intended base-memory scan never happens. * * mptable_search_sig()'s mapdev/scan body is elided (no device access * in userland); the KKASSERT and the arithmetic are verbatim. */ #include <stdio.h> #include <stdlib.h> #include <setjmp.h> typedef unsigned int u_int; typedef unsigned int u_int32_t; static sigjmp_buf panic_jmp; static int in_panic_scope; static char panic_msg[256]; static void kpanic(void) { snprintf(panic_msg, sizeof(panic_msg), "assertion \"target != 0\" failed in mptable_search_sig " "at mptable.c:368"); if (in_panic_scope) { in_panic_scope = 0; siglongjmp(panic_jmp, 1); } fprintf(stderr, "KERNEL PANIC: %s\n", panic_msg); exit(86); } #define KKASSERT(x) do { if (!(x)) kpanic(); } while (0) /* verbatim head of mptable_search_sig (mptable.c:361-371) */ static long mptable_search_sig(u_int32_t target, int count) { (void)count; KKASSERT(target != 0); /* mptable.c:368 */ /* pmap_mapdev(target, count*4) + _MP_ scan elided */ return 0; } /* verbatim else-branch of mptable_search (mptable.c:282-287) */ static int search_base_memory_scan(u_int base_memory) { u_int32_t target; long x; target = (u_int32_t)((base_memory - 1) * 1024); /* mptable.c:284 */ in_panic_scope = 1; if (sigsetjmp(panic_jmp, 1) != 0) { printf(" base_memory=%-4u -> target=0x%08x KERNEL PANIC -> %s\n", base_memory, target, panic_msg); return 1; } x = mptable_search_sig(target, 1024 / 4); in_panic_scope = 0; if (target + 1024 < target) printf(" base_memory=%-4u -> target=0x%08x scan [%08x..%08x]: " "WRAPPED past 4GB, top-of-4GB MMIO hole, not base memory\n", base_memory, target, target, target + 1024); else if (target >= 0xF00000) printf(" base_memory=%-4u -> target=0x%08x scan [%08x..%08x]: " "high MMIO hole, not the intended base-memory scan\n", base_memory, target, target, target + 1024); else printf(" base_memory=%-4u -> target=0x%08x scan [%08x..%08x]: " "%s (sig not found: 0)\n", base_memory, target, target, target + 1024, (x > 0) ? "signature found" : "sane region"); return 0; } int main(void) { u_int bm[] = { 0, 1, 2, 16, 511, 638, 639 }; unsigned i; int panics = 0; printf("mptable_search() base-memory branch, ebda_addr == 0 " "(verbatim arithmetic, mptable.c:284/368):\n"); for (i = 0; i < sizeof(bm) / sizeof(bm[0]); i++) panics += search_base_memory_scan(bm[i]); printf("\nresult: base_memory==1 -> deterministic boot-time KKASSERT panic; " "base_memory==0 -> wrong-region scan at 0xFFFFFC00 " "(crosses the 4GB wrap); panics=%d\n", panics); return 0; } |