1 /* 2 * fault-model.c -- fault injection code for drivers 3 * 4 * Copyright (C) 2003 Mike Swift 5 * Copyright (c) 1999 Wee Teck Ng 6 * 7 * The source code in this file can be freely used, adapted, 8 * and redistributed in source or binary form, so long as an 9 * acknowledgment appears in derived source files. No warranty 10 * is attached; we cannot take responsibility for errors or 11 * fitness for use. 12 * 13 */ 14 15 16 /* 17 * Fault injector for testing the usefulness of NOOKS 18 * 19 * Adapted from the SWIFI tools used by Wee Teck Ng to evaluate the RIO 20 * file cache at the University of Michigan 21 * 22 */ 23 24 /* 25 * This tool can inject faults into modules, whether they are loaded into a 26 * nook or loaded into the kernel (for comparison testing). 27 * 28 * There are several classes of faults emulated: 29 * - Corruption of text 30 * - corruption 31 * - simulated programming faults 32 * - skip initialization (immediate write to EBP-x) 33 * - remove instruction (replace with NOP) 34 * - incorrect source/destination (corrupted) 35 * - remove jmp or rep instruction 36 * - change address computation for memory access (not stack) 37 * - change termination condition for loop (change repeat to repeat 38 * while equal, change condition to !condition) 39 * - remove instructions loading registers from arguments (ebp+x) 40 */ 41 42 #include <stdio.h> 43 #include <assert.h> 44 45 #include "ddb.h" 46 #include "db_sym.h" 47 #include "swifi.h" 48 49 #include "extra.h" 50 51 #define PDEBUG(args) /* (printf args) */ 52 53 #define NOP 0x90 54 55 static int text_fault(int type, unsigned long btext, unsigned long text_size); 56 57 static int randomFaults[] = { 58 TEXT_FAULT, 59 NOP_FAULT, 60 SRC_FAULT, 61 DST_FAULT, 62 PTR_FAULT, 63 LOOP_FAULT, 64 INTERFACE_FAULT 65 }; 66 67 void 68 swifi_inject_fault(char * module_name, 69 unsigned long faultType, 70 unsigned long randomSeed, 71 unsigned long numFaults) 72 { 73 unsigned long btext, etext, text_size; 74 int type; 75 76 /* default number of faults is 5 */ 77 if (numFaults == 0) numFaults = 5; 78 79 srandom(randomSeed); 80 81 load_nlist(module_name, &btext, &etext); 82 83 text_size = etext - btext; 84 85 PDEBUG(("text=%lx-%lx, size=%lx\n", btext, etext, text_size)); 86 87 while (numFaults) { 88 if ((type = faultType) == RANDOM_FAULT) 89 type = randomFaults[random() % 90 (sizeof(randomFaults) / sizeof(randomFaults[0]))]; 91 92 if (text_fault(type, btext, text_size)) 93 numFaults--; 94 } 95 } 96 97 static int text_fault(int type, unsigned long btext, unsigned long text_size) 98 { 99 unsigned long *addr, taddr; 100 int j, flip_bit, len, prefix; 101 unsigned char *c; 102 103 /* inject faults into text space */ 104 105 addr = (unsigned long *) 106 (btext + ((unsigned long) (random()&~0xf) % text_size)); 107 108 /* now the tricky part */ 109 110 taddr=(unsigned long) addr; 111 if (type != TEXT_FAULT) { 112 addr = (unsigned long *) find_faulty_instr(taddr, type, &len); 113 /* do it over again if we can't find the right instruction */ 114 if (!addr || !len) 115 return FALSE; 116 } 117 118 PDEBUG(("target addr=%lx, instr addr=%p, %lx=>", taddr, addr, 119 text_read_ul(addr))); 120 121 switch (type) { 122 case TEXT_FAULT: 123 flip_bit = random() & 0x1f; 124 PDEBUG(("flip bit %d => ", flip_bit)); 125 flip_bit = 1 << flip_bit; 126 127 text_write_ul(addr, text_read_ul(addr)^flip_bit); 128 129 break; 130 131 case NOP_FAULT: 132 case INIT_FAULT: 133 case BRANCH_FAULT: 134 case INTERFACE_FAULT: 135 case IRQ_FAULT: 136 c = (unsigned char *) addr; 137 138 for (j = 0; j < len; j++) { 139 /* replace these bytes with NOP (*c=NOP) */ 140 text_write_ub(c, NOP); 141 142 c++; 143 } 144 145 break; 146 147 case DST_FAULT: 148 case SRC_FAULT: 149 /* skip thru the prefix and opcode, and flip bits in following bytes */ 150 c=(unsigned char *) addr; 151 do { 152 switch (text_read_ub(c)) { 153 case 0x66: case 0x67: case 0x26: case 0x36: 154 case 0x2e: case 0x3e: case 0x64: case 0x65: 155 case 0xf0: case 0xf2: case 0xf3: 156 prefix = 1; 157 break; 158 default: 159 prefix = 0; 160 break; 161 } 162 if (prefix) { 163 c++; 164 } 165 } while (prefix); 166 if(text_read_ub(c)>=0xd8 && text_read_ub(c)<=0xdf) { 167 /* don't mess with fp instruction, yet */ 168 PDEBUG(("floating point instruction, bailing out\n")); 169 return FALSE; 170 } 171 if(text_read_ub(c)==0x0f) { 172 c++; 173 } 174 if(text_read_ub(c)==0x0f) { 175 c++; 176 } 177 c++; 178 len = len-((long) c - (long) addr); 179 if (len == 0) 180 { 181 PDEBUG(("text_fault: len = %d\n", len)); 182 return FALSE; 183 } 184 flip_bit = random() % (len*8); 185 PDEBUG(("flip bit %d (len=%d) => ", flip_bit, len)); 186 for(j=0; j<len; j++) { 187 /* go to the right byte */ 188 if(flip_bit<8) { 189 flip_bit = 1 << flip_bit; 190 191 text_write_ub(c, (text_read_ub(c)^flip_bit)); 192 193 j=len; 194 } 195 c++; 196 flip_bit = flip_bit-8; 197 } 198 199 break; 200 201 case PTR_FAULT: 202 /* 5f) ptr: if instruction has regmodrm byte (i_has_modrm), 203 * flip 1 bit in lower byte (0x0f) or any bit in following 204 * bytes (sib, imm or disp). 205 */ 206 c=(unsigned char *) addr; 207 do { 208 switch (text_read_ub(c)) { 209 case 0x66: case 0x67: case 0x26: case 0x36: 210 case 0x2e: case 0x3e: case 0x64: case 0x65: 211 case 0xf0: case 0xf2: case 0xf3: 212 prefix = 1; 213 break; 214 default: 215 prefix = 0; 216 break; 217 } 218 if (prefix) { 219 c++; 220 } 221 } while (prefix); 222 if(text_read_ub(c)>=0xd8 && text_read_ub(c)<=0xdf) { 223 /* don't mess with fp instruction, yet */ 224 PDEBUG(("floating point instruction, bailing out\n")); 225 return FALSE; 226 } 227 if(text_read_ub(c)==0x0f) { 228 c++; 229 } 230 if(text_read_ub(c)==0x0f) { 231 c++; 232 } 233 c++; 234 len = len-((long) c - (long) addr); 235 flip_bit = random() % (len*8-4); 236 PDEBUG(("flip bit %d (len=%d) => ", flip_bit, len)); 237 238 /* mod/rm byte is special */ 239 240 if (flip_bit < 4) { 241 flip_bit = 1 << flip_bit; 242 243 text_write_ub(c, text_read_ub(c)^flip_bit); 244 } 245 c++; 246 flip_bit=flip_bit-4; 247 248 for(j=1; j<len; j++) { 249 /* go to the right byte */ 250 if (flip_bit<8) { 251 flip_bit = 1 << flip_bit; 252 253 text_write_ub(c, text_read_ub(c)^flip_bit); 254 255 j=len; 256 } 257 c++; 258 flip_bit = flip_bit-8; 259 } 260 261 break; 262 263 case LOOP_FAULT: 264 c=(unsigned char *) addr; 265 /* replace rep with repe, and vice versa */ 266 if(text_read_ub(c)==0xf3) { 267 text_write_ub(c, 0xf2); 268 } else if(text_read_ub(c)==0xf2) { 269 text_write_ub(c, 0xf3); 270 } else if( (text_read_ub(c)&0xf0)==0x70 ) { 271 /* if we've jxx imm8 instruction, 272 * incl even byte instruction, eg jo (70) to jno (71) 273 * decl odd byte instruction, eg jnle (7f) to jle (7e) 274 */ 275 if(text_read_ub(c)%2 == 0) { 276 text_write_ub(c, text_read_ub(c)+1); 277 } else { 278 text_write_ub(c, text_read_ub(c)-1); 279 } 280 } else if(text_read_ub(c)==0x66 || text_read_ub(c)==0x67) { 281 /* override prefix */ 282 c++; 283 } else if(text_read_ub(c++)==0xf && (text_read_ub(c)&0xf0)==0x80 ) { 284 /* if we've jxx imm16/32 instruction, 285 * incl even byte instruction, eg jo (80) to jno (81) 286 * decl odd byte instruction, eg jnle (8f) to jle (8e) 287 */ 288 if(text_read_ub(c)%2 == 0) { 289 text_write_ub(c, text_read_ub(c)+1); 290 } else { 291 text_write_ub(c, text_read_ub(c)-1); 292 } 293 } 294 295 break; 296 297 case STOP_FAULT: 298 text_write_ub(addr, BKPT_INST); 299 300 break; 301 302 default: 303 assert(0); 304 } 305 306 return TRUE; 307 } 308