DF-4337 / atom_harness_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 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 | /* * atom_harness_fixed.c — the SAME cases as atom_harness_guest.c but with * the FIXED logic from findings/poc/DF-433{7,8,9}/fix.diff applied to the * mirrored functions. All cases must exit 0 (no guard-page traps) and * reject/terminate cleanly: that is the logic-level fix validation. * * Build: cc -O1 -g -o atom_harness_fixed atom_harness_fixed.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <stdbool.h> #include <sys/mman.h> typedef uint16_t u16; static inline uint8_t get_u8(void *bios, int ptr) { return ((unsigned char *)bios)[ptr]; } static inline uint16_t get_u16(void *bios, int ptr) { return get_u8(bios, ptr) | (((uint16_t)get_u8(bios, ptr + 1)) << 8); } #define CU8(ptr) get_u8(ctx->bios, (ptr)) #define CU16(ptr) get_u16(ctx->bios, (ptr)) #define CSTR(ptr) (((char *)(ctx->bios)) + (ptr)) struct atom_context { void *bios; int bios_size; uint32_t cmd_table, data_table; uint16_t *iio; uint16_t data_block; }; /* DF-4337 fix: central bounds helper */ static bool atom_in_bios(const struct atom_context *ctx, int off, int len) { return off >= 0 && len >= 0 && off <= ctx->bios_size - len; } static void *guarded_alloc(size_t sz) { long ps = 4096; size_t guard = (size_t)16 * 1024 * 1024; size_t len = (size_t)ps + guard; char *base = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (base == MAP_FAILED) { perror("mmap"); exit(3); } if (mprotect(base + ps, guard, PROT_NONE) != 0) { perror("mprotect"); exit(3); } return base + ps - sz; } /* FIXED atom_parse_data_header (DF-4337 fix.diff) */ bool atom_parse_data_header(struct atom_context *ctx, int index, uint16_t * size, uint8_t * frev, uint8_t * crev, uint16_t * data_start) { int offset = index * 2 + 4; u16 *mdt = (u16 *)((char *)ctx->bios + ctx->data_table + 4); int idx; if (index < 0 || !atom_in_bios(ctx, ctx->data_table + offset, 2)) return false; idx = CU16(ctx->data_table + offset); if (!mdt[index]) return false; if (!atom_in_bios(ctx, idx, 4) || !atom_in_bios(ctx, idx, CU16(idx))) return false; if (size) *size = CU16(idx); if (frev) *frev = CU8(idx + 2); if (crev) *crev = CU8(idx + 3); *data_start = idx; return true; } #define ATOM_IIO_START 1 #define ATOM_IIO_END 9 static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 }; /* FIXED atom_index_iio (DF-4337 + DF-4338 fix.diffs) */ static void atom_index_iio(struct atom_context *ctx, int base) { ctx->iio = calloc(256, 2); if (!ctx->iio) return; while (atom_in_bios(ctx, base, 2) && CU8(base) == ATOM_IIO_START) { ctx->iio[CU8(base + 1)] = base + 2; base += 2; while (atom_in_bios(ctx, base, 1) && CU8(base) != ATOM_IIO_END) { int op = CU8(base); if (op > ATOM_IIO_END) return; base += atom_iio_len[op]; } base += 3; } } /* FIXED atom_parse name loop (DF-4337 bound + DF-4339 termination) */ static void atom_parse_name(struct atom_context *ctx, int msg_ptr) { char *str; char name[512] = { 0 }; int i; if (!atom_in_bios(ctx, msg_ptr, 1)) { printf(" msg ptr beyond image: rejected\n"); return; } str = CSTR(msg_ptr); while (*str && ((*str == '\n') || (*str == '\r'))) str++; for (i = 0; i < 511; i++) { if (!atom_in_bios(ctx, msg_ptr + (int)(str - (char *)ctx->bios) + i, 1)) break; name[i] = str[i]; if (name[i] < '.' || name[i] > 'z') { name[i] = 0; break; } } printf(" strlen(name) after loop = %zu (<= 511: always terminated)\n", strlen(name)); } int main(int argc, char **argv) { const char *cs = argc > 1 ? argv[1] : "data_header"; printf("case: %s (FIXED logic)\n", cs); if (!strcmp(cs, "data_header")) { struct atom_context sctx, *ctx = &sctx; memset(&sctx, 0, sizeof(sctx)); ctx->bios = guarded_alloc(512); ctx->bios_size = 512; /* DF-4337 plumbing */ ctx->data_table = 0x20; ((uint8_t *)ctx->bios)[0x24] = 0x00; /* mdt[0] = 0x8000 */ ((uint8_t *)ctx->bios)[0x25] = 0x80; uint16_t size = 0, data_start = 0; bool ok = atom_parse_data_header(ctx, 0, &size, NULL, NULL, &data_start); printf(" result: ok=%d (expected 0: entry 0x8000 rejected vs bios_size=512)\n", ok); return ok ? 1 : 0; } if (!strcmp(cs, "iio")) { struct atom_context sctx, *ctx = &sctx; memset(&sctx, 0, sizeof(sctx)); ctx->bios = guarded_alloc(512); ctx->bios_size = 512; uint8_t *b = ctx->bios; b[0x40] = ATOM_IIO_START; b[0x41] = 0x05; b[0x42] = 200; /* opcode 200: rejected by fix */ atom_index_iio(ctx, 0x40); printf(" result: walk stopped cleanly on opcode 200 (no trap)\n"); return 0; } if (!strcmp(cs, "name")) { struct atom_context sctx, *ctx = &sctx; memset(&sctx, 0, sizeof(sctx)); size_t sz = 512; ctx->bios = guarded_alloc(sz); ctx->bios_size = sz; memset((uint8_t *)ctx->bios + sz - 300, 'B', 300); atom_parse_name(ctx, (int)(sz - 300)); printf(" result: copy bounded at image end (no trap)\n"); return 0; } if (!strcmp(cs, "name_nul")) { static uint8_t backing[1024]; memset(backing, 'C', sizeof(backing)); struct atom_context sctx, *ctx = &sctx; memset(&sctx, 0, sizeof(sctx)); ctx->bios = backing; ctx->bios_size = 1024; atom_parse_name(ctx, 0); return 0; } fprintf(stderr, "unknown case %s\n", cs); return 2; } |