xref: /minix/minix/commands/swifi/fault_model.c (revision 0a6a1f1d)
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