DF-1374 / 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 | /* * DF-1374 harness: OOB heap write via unchecked firmware-controlled * DeviceIndex in _mapping_process_dpm_pg0 (mps_mapping.c). * * This is the MPS driver's twin of DF-1282 (the mpr driver's identical bug). * OBJECT-LEVEL proof of the primitive: the mps driver cannot attach on the * audit QEMU guest (no LSI/Avago SAS HBA present), so the vulnerable path is * not runtime-reachable here. This harness replicates the exact kernel struct * (dev_mapping_table) and the exact unguarded indexing from * _mapping_process_dpm_pg0 with an attacker/firmware-controlled DeviceIndex * to PROVE the OOB write primitive is real. * * Cited path: sys/dev/raid/mps/mps_mapping.c:1495 (dev_idx = le16toh(DeviceIndex)) * sys/dev/raid/mps/mps_mapping.c:1497 (IR path WITH bounds check) * sys/dev/raid/mps/mps_mapping.c:1544 (Enc/Slot sink, NO check) * sys/dev/raid/mps/mps_mapping.c:1545 (num_slots loop, NO check) * sys/dev/raid/mps/mps_mapping.c:1567 (Device-Persistence sink, NO check) * * Build: cc -O2 -o harness harness.c * Run: ./harness */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> /* Mirror of sys/dev/raid/mps/mpsvar.h dev_mapping_table */ struct dev_mapping_table { uint64_t physical_id; uint32_t device_info; uint32_t phy_bits; uint16_t dpm_entry_num; uint16_t dev_handle; uint16_t reserved1; uint16_t id; uint8_t missing_count; uint8_t init_complete; uint8_t TLR_bits; uint8_t reserved2; }; #define MAX_DEVICES 264u /* MaxTargets(256)+max_volumes(8) typical */ #define GUARD_N 64 /* guard entries after the allocation */ int main(void) { struct dev_mapping_table *table = calloc(MAX_DEVICES + GUARD_N, sizeof(*table)); if (!table) { perror("calloc"); return 1; } for (unsigned g = MAX_DEVICES; g < MAX_DEVICES + GUARD_N; g++) memset(&table[g], 0xAA, sizeof(table[g])); printf("[DF-1374] mapping_table allocated for max_devices=%u entries " "(sizeof(entry)=%zu)\n", MAX_DEVICES, sizeof(*table)); /* Replicate the Enc/Slot path of _mapping_process_dpm_pg0. * dev_idx is firmware-controlled (mps_mapping.c:1495). The IR path * (:1497) bounds-checks it; the Enc/Slot (:1544) and Device-Persistence * (:1567) paths do NOT. num_slots is firmware-controlled too. */ uint32_t dev_idx = MAX_DEVICES + 2; /* firmware DeviceIndex >= max_devices */ uint16_t num_slots = 4; uint32_t map_idx; struct dev_mapping_table *mt_entry; printf("[DF-1374] attacker/firmware DeviceIndex=%u, num_slots=%u\n", dev_idx, num_slots); if (dev_idx >= MAX_DEVICES) { printf("[DF-1374] BUG CONFIRMED: dev_idx=%u >= max_devices=%u -> " "write at mapping_table[%u] is %zu bytes PAST the allocation " "(into the adjacent slab object)\n", dev_idx, MAX_DEVICES, dev_idx, (size_t)(dev_idx - MAX_DEVICES) * sizeof(*table)); } /* Execute the unguarded loop exactly as mps_mapping.c:1544-1563 */ mt_entry = &table[dev_idx]; /* :1544 OOB pointer */ for (map_idx = dev_idx; map_idx < (dev_idx + num_slots); map_idx++, mt_entry++) { /* :1545 */ mt_entry->physical_id = 0x4141414141414141ULL; mt_entry->phy_bits = 0x42424242; mt_entry->id = dev_idx; mt_entry->dpm_entry_num = 1; mt_entry->missing_count = 0; mt_entry->device_info = 0x43434343; /* MPS_DEV_RESERVED stand-in */ } unsigned hits = 0; for (unsigned g = MAX_DEVICES; g < MAX_DEVICES + GUARD_N; g++) { uint8_t *p = (uint8_t *)&table[g], *end = p + sizeof(table[g]); for (; p < end; p++) if (*p != 0xAA) { hits++; break; } } printf("[DF-1374] guard/slab region corrupted: %s (%u of %u entries " "touched)\n", hits ? "YES -> next heap object(s) overwritten" : "no", hits, GUARD_N); if (dev_idx >= MAX_DEVICES || dev_idx + num_slots > MAX_DEVICES) { printf("[DF-1374] FIX: with bounds check, write SKIPPED " "(dev_idx=%u >= max_devices=%u) -> no corruption\n", dev_idx, MAX_DEVICES); } free(table); return hits ? 0 : 2; } |