DF-5477 / df5477_fixed.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 | /* * DF-5477 fix-validation harness — the same verbatim efi_get_table() walk * with ONLY the fix.diff changes applied (entry-count cap + PHYS_TO_DMAP * translation of the physical st_cfgtbl + ct_data bound check). * * Part A' (sysctl debug.df5477f=1): same lied-about st_entries=200 -> * fixed code returns EOVERFLOW, no OOB walk, nothing found. * Part B' (sysctl debug.df5477f=2): physical cfgtbl 0x7FB1C000 -> * translated into the DMAP before dereference (no wild-pointer fault; * on real EFI hardware this reads the actual firmware config table). * Part B2' (sysctl debug.df5477f=3): same, using a guest-backed physical * address (0x1000000) so the dereference demonstrably completes. */ #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> #define DF_CFGTBL_MAX 256 static struct efi_systbl *df_systbl; static struct efi_cfgtbl *df_cfgtbl; static MALLOC_DEFINE(M_DF5477F, "df5477f", "DF-5477 fix validation"); /* efi_get_table() WITH fix.diff applied */ static int df_efi_get_table_fixed(struct uuid *uuid, void **ptr) { struct efi_cfgtbl *ct; u_long count; if (df_cfgtbl == NULL) return (ENXIO); count = df_systbl->st_entries; if (count > DF_CFGTBL_MAX) /* FIX: cap the walk */ return (EOVERFLOW); ct = (struct efi_cfgtbl *)PHYS_TO_DMAP( /* FIX: physical -> DMAP */ (vm_paddr_t)(uintptr_t)df_systbl->st_cfgtbl); while (count--) { if (!bcmp(&ct->ct_uuid, uuid, sizeof(*uuid))) { if (ct->ct_data >= DMAP_MAX_ADDRESS - DMAP_MIN_ADDRESS) return (ERANGE); /* FIX: bound ct_data */ *ptr = (void *)PHYS_TO_DMAP(ct->ct_data); return (0); } ct++; } 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; const int lie_entries = 512; /* > DF_CFGTBL_MAX of 256 */ int error; void *ptr = NULL; st = kmalloc(sizeof(*st), M_DF5477F, M_WAITOK | M_ZERO); st->st_entries = lie_entries; st->st_cfgtbl = 0x1000000UL; /* guest-backed phys */ df_systbl = st; df_cfgtbl = (struct efi_cfgtbl *)(uintptr_t)st->st_cfgtbl; kprintf("DF-5477A': st_entries=%d lie (> cap %d), FIXED code: " "expect EOVERFLOW (no OOB walk)\n", lie_entries, DF_CFGTBL_MAX); error = df_efi_get_table_fixed((__DECONST(struct uuid *, &df_query)), &ptr); kprintf("DF-5477A': result error=%d (EOVERFLOW=%d), ptr=%p -> %s\n", error, EOVERFLOW, ptr, error == EOVERFLOW ? "FIX HOLDS (walk refused)" : error == 0 ? "FOUND (fix failed)" : "other"); return (0); } static void df_part_b(vm_paddr_t phys) { static struct efi_systbl st; struct uuid q; void *p = NULL; memset(&q, 0, sizeof(q)); st.st_entries = 2; st.st_cfgtbl = phys; df_systbl = &st; df_cfgtbl = (struct efi_cfgtbl *)(uintptr_t)phys; kprintf("DF-5477B': st_cfgtbl physical %#jx -> FIXED code DMAPs it to " "%p before deref\n", (uintmax_t)phys, (void *)PHYS_TO_DMAP(phys)); df_efi_get_table_fixed(&q, &p); /* no fault expected */ kprintf("DF-5477B': returned without fault (error path normal)\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); switch (val) { case 1: return (df_part_a()); case 2: df_part_b(0x7FB1C000UL); /* firmware-style phys, ~2GB */ break; case 3: df_part_b(0x1000000UL); /* guest RAM-backed phys */ break; } return (0); } static int df_modevent(module_t m, int event, void *arg __unused) { switch (event) { case MOD_LOAD: { SYSCTL_PROC(_debug, OID_AUTO, df5477f, CTLTYPE_INT | CTLFLAG_RW, NULL, 0, df_sysctl, "I", "1=cap test 2=fw-phys DMAP 3=ram-phys DMAP"); kprintf("DF-5477 fix-validation harness loaded " "(debug.df5477f)\n"); return (0); } case MOD_UNLOAD: return (0); default: return (EOPNOTSUPP); } } static moduledata_t df5477f_mod = { "df5477_fixed", df_modevent, NULL }; DECLARE_MODULE(df5477_fixed, df5477f_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); |