DF-3843 / map_sync_overflow_proof.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 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | /* * DF-3843 arithmetic proof (userland, standalone). * * Reproduces the exact struct layout math of the mrsas RAID-map sync path * using the definitions copied verbatim from sys/dev/raid/mrsas/mrsas.h, * and shows that: * * 1. the destination buffer allocated in mrsas_setup_raidmap() * (mrsas.c:1645) is sizeof(MR_FW_RAID_MAP) * + sizeof(MR_LD_SPAN_MAP)*(MAX_LOGICAL_DRIVES-1) bytes, * 2. the write loop in mrsas_sync_map_info() (mrsas.c:3220-3224) writes * sizeof(MR_LD_TARGET_SYNC) * ldCount bytes at offset 0 of that buffer, * where ldCount is the FULL 32-bit firmware field (mrsas.c:3207), * 3. MR_ValidateMapInfo() (mrsas_fp.c:257-265) only checks that * totalSize == (sizeof(MR_FW_RAID_MAP) - sizeof(MR_LD_SPAN_MAP) * + sizeof(MR_LD_SPAN_MAP)*ldCount) (u32 arithmetic) * -- a firmware that supplies a matching (totalSize, ldCount) pair for * ANY ldCount passes validation; nothing bounds ldCount <= 64. * * Expected output shows a concrete (totalSize, ldCount=65536) pair that * passes validation and overwrites ~90 KB past the 172,200-byte map buffer. */ #include <stdio.h> #include <stdint.h> #include <string.h> #include <sys/types.h> /* ---- verbatim from sys/dev/raid/mrsas/mrsas.h ---- */ #define MAX_SPAN_DEPTH 8 #define MAX_QUAD_DEPTH MAX_SPAN_DEPTH #define MAX_RAIDMAP_SPAN_DEPTH (MAX_SPAN_DEPTH) #define MAX_ROW_SIZE 32 #define MAX_RAIDMAP_ROW_SIZE (MAX_ROW_SIZE) #define MAX_LOGICAL_DRIVES 64 #define MAX_RAIDMAP_LOGICAL_DRIVES (MAX_LOGICAL_DRIVES) #define MAX_RAIDMAP_VIEWS (MAX_LOGICAL_DRIVES) #define MAX_ARRAYS 128 #define MAX_RAIDMAP_ARRAYS (MAX_ARRAYS) #define MAX_PHYSICAL_DEVICES 256 #define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES) typedef struct _MR_DEV_HANDLE_INFO { u_int16_t curDevHdl; u_int8_t validHandles; u_int8_t reserved; u_int16_t devHandle[2]; } MR_DEV_HANDLE_INFO; typedef struct _MR_ARRAY_INFO { u_int16_t pd[MAX_RAIDMAP_ROW_SIZE]; } MR_ARRAY_INFO; typedef struct _MR_QUAD_ELEMENT { u_int64_t logStart; u_int64_t logEnd; u_int64_t offsetInSpan; u_int32_t diff; u_int32_t reserved1; } MR_QUAD_ELEMENT; typedef struct _MR_SPAN_INFO { u_int32_t noElements; u_int32_t reserved1; MR_QUAD_ELEMENT quad[MAX_RAIDMAP_SPAN_DEPTH]; } MR_SPAN_INFO; typedef struct _MR_LD_SPAN_ { u_int64_t startBlk; u_int64_t numBlks; u_int16_t arrayRef; u_int8_t spanRowSize; u_int8_t spanRowDataSize; u_int8_t reserved[4]; } MR_LD_SPAN; typedef struct _MR_SPAN_BLOCK_INFO { u_int64_t num_rows; MR_LD_SPAN span; MR_SPAN_INFO block_span_info; } MR_SPAN_BLOCK_INFO; typedef struct _MR_LD_RAID { struct { u_int32_t fpCapable :1; u_int32_t reserved5 :3; u_int32_t ldPiMode :4; u_int32_t pdPiMode :4; u_int32_t encryptionType :8; u_int32_t fpWriteCapable :1; u_int32_t fpReadCapable :1; u_int32_t fpWriteAcrossStripe :1; u_int32_t fpReadAcrossStripe :1; u_int32_t fpNonRWCapable :1; u_int32_t reserved4 :7; } capability; u_int32_t reserved6; u_int64_t size; u_int8_t spanDepth; u_int8_t level; u_int8_t stripeShift; u_int8_t rowSize; u_int8_t rowDataSize; u_int8_t writeMode; u_int8_t PRL; u_int8_t SRL; u_int16_t targetId; u_int8_t ldState; u_int8_t regTypeReqOnWrite; u_int8_t modFactor; u_int8_t regTypeReqOnRead; u_int16_t seqNum; struct { u_int32_t ldSyncRequired:1; u_int32_t regTypeReqOnReadLsValid:1; u_int32_t reserved:30; } flags; u_int8_t LUN[8]; u_int8_t fpIoTimeoutForLd; u_int8_t reserved2[3]; u_int32_t logicalBlockLength; struct { u_int32_t LdPiExp:4; u_int32_t LdLogicalBlockExp:4; u_int32_t reserved1:24; } exponent; u_int8_t reserved3[0x80-0x38]; } MR_LD_RAID; typedef struct _MR_LD_SPAN_MAP { MR_LD_RAID ldRaid; u_int8_t dataArmMap[MAX_RAIDMAP_ROW_SIZE]; MR_SPAN_BLOCK_INFO spanBlock[MAX_RAIDMAP_SPAN_DEPTH]; } MR_LD_SPAN_MAP; typedef struct _MR_FW_RAID_MAP { u_int32_t totalSize; union { struct { u_int32_t maxLd; u_int32_t maxSpanDepth; u_int32_t maxRowSize; u_int32_t maxPdCount; u_int32_t maxArrays; } validationInfo; u_int32_t version[5]; u_int32_t reserved1[5]; } raid_desc; u_int32_t ldCount; u_int32_t Reserved1; u_int8_t ldTgtIdToLd[MAX_RAIDMAP_LOGICAL_DRIVES+MAX_RAIDMAP_VIEWS]; u_int8_t fpPdIoTimeoutSec; u_int8_t reserved2[7]; MR_ARRAY_INFO arMapInfo[MAX_RAIDMAP_ARRAYS]; MR_DEV_HANDLE_INFO devHndlInfo[MAX_RAIDMAP_PHYSICAL_DEVICES]; MR_LD_SPAN_MAP ldSpanMap[1]; } MR_FW_RAID_MAP; typedef struct _MR_FW_RAID_MAP_ALL { MR_FW_RAID_MAP raidMap; MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES - 1]; } MR_FW_RAID_MAP_ALL; typedef struct _MR_LD_TARGET_SYNC { u_int8_t targetId; u_int8_t reserved; u_int16_t seqNum; } MR_LD_TARGET_SYNC; /* ---- end verbatim ---- */ int main(void) { const uint32_t map_sz = (uint32_t)(sizeof(MR_FW_RAID_MAP) + sizeof(MR_LD_SPAN_MAP) * (MAX_LOGICAL_DRIVES - 1)); const uint32_t entry = (uint32_t)sizeof(MR_LD_TARGET_SYNC); const uint32_t capacity = map_sz / entry; uint32_t ldCount = 65536; uint32_t totalSize; printf("sizeof(MR_FW_RAID_MAP) = %u (header comment says 0x3288=%u)\n", (unsigned)sizeof(MR_FW_RAID_MAP), 0x3288u); printf("sizeof(MR_LD_SPAN_MAP) = %u (header comment says 0x9E0=%u)\n", (unsigned)sizeof(MR_LD_SPAN_MAP), 0x9E0u); printf("sizeof(MR_FW_RAID_MAP_ALL) = %u\n", (unsigned)sizeof(MR_FW_RAID_MAP_ALL)); printf("sizeof(MR_LD_TARGET_SYNC) = %u\n", entry); printf("map_sz (mrsas.c:1645) = %u <- bus_dmamem_alloc size\n", map_sz); printf("capacity in sync entries = %u (max ldCount before OOB)\n", capacity); /* MR_ValidateMapInfo check, mrsas_fp.c:257-260 */ totalSize = (uint32_t)(sizeof(MR_FW_RAID_MAP) - sizeof(MR_LD_SPAN_MAP) + ((size_t)sizeof(MR_LD_SPAN_MAP) * ldCount)); printf("\nFirmware supplies ldCount=%u, totalSize=0x%x:\n", ldCount, totalSize); printf(" MR_ValidateMapInfo: totalSize(0x%x) == expected(0x%x) -> PASSES\n", totalSize, totalSize); printf(" mrsas_sync_map_info loop writes %u * %u = %u bytes " "into a %u-byte buffer\n", ldCount, entry, ldCount * entry, map_sz); printf(" => %d bytes written PAST the end of the DMA allocation\n", (int)((uint64_t)ldCount * entry - map_sz)); printf(" => %u entries land fully out of bounds, each entry =\n", ldCount - capacity); printf(" { targetId: FW u8, reserved: 0x00, seqNum: FW u16 }\n"); /* the read side: MR_GetLDTgtId/MR_LdRaidGet index ldSpanMap[i], i < ldCount */ printf("\nread side: MR_LdRaidGet(i)/MR_GetLDTgtId(i) read ldSpanMap[i] for\n" " i up to %u; buffer holds %d span maps -> OOB read too\n", ldCount - 1, (int)(sizeof(MR_FW_RAID_MAP_ALL) / sizeof(MR_LD_SPAN_MAP))); if ((uint64_t)ldCount * entry <= map_sz) { printf("\nPROOF FAILED: no overflow\n"); return (1); } printf("\nPROOF OK: loop length is firmware-controlled and unbounded; " "validation does not bound ldCount\n"); return (0); } |