xref: /minix3/minix/commands/swifi/fault_model.c (revision 875abb872412bde4d3ba5da66423f55431e19dcf)
1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc  * fault-model.c -- fault injection code for drivers
3433d6423SLionel Sambuc  *
4433d6423SLionel Sambuc  * Copyright (C) 2003 Mike Swift
5433d6423SLionel Sambuc  * Copyright (c) 1999 Wee Teck Ng
6433d6423SLionel Sambuc  *
7433d6423SLionel Sambuc  * The source code in this file can be freely used, adapted,
8433d6423SLionel Sambuc  * and redistributed in source or binary form, so long as an
9433d6423SLionel Sambuc  * acknowledgment appears in derived source files.  No warranty
10*875abb87SDavid van Moolenbroek  * is attached; we cannot take responsibility for errors or
11433d6423SLionel Sambuc  * fitness for use.
12433d6423SLionel Sambuc  *
13433d6423SLionel Sambuc  */
14433d6423SLionel Sambuc 
15433d6423SLionel Sambuc 
16433d6423SLionel Sambuc /*
17433d6423SLionel Sambuc  * Fault injector for testing the usefulness of NOOKS
18433d6423SLionel Sambuc  *
19433d6423SLionel Sambuc  * Adapted from the SWIFI tools used by Wee Teck Ng to evaluate the RIO
20433d6423SLionel Sambuc  * file cache at the University of Michigan
21433d6423SLionel Sambuc  *
22433d6423SLionel Sambuc  */
23433d6423SLionel Sambuc 
24433d6423SLionel Sambuc /*
25433d6423SLionel Sambuc  * This tool can inject faults into modules, whether they are loaded into a
26433d6423SLionel Sambuc  * nook or loaded into the kernel (for comparison testing).
27433d6423SLionel Sambuc  *
28433d6423SLionel Sambuc  * There are several classes of faults emulated:
29433d6423SLionel Sambuc  * - Corruption of text
30433d6423SLionel Sambuc  *    - corruption
31433d6423SLionel Sambuc  *    - simulated programming faults
32433d6423SLionel Sambuc  *         - skip initialization (immediate write to EBP-x)
33433d6423SLionel Sambuc  *         - remove instruction (replace with NOP)
34433d6423SLionel Sambuc  *	   - incorrect source/destination (corrupted)
35433d6423SLionel Sambuc  *         - remove jmp or rep instruction
36433d6423SLionel Sambuc  *         - change address computation for memory access (not stack)
37433d6423SLionel Sambuc  *	   - change termination condition for loop (change repeat to repeat
38*875abb87SDavid van Moolenbroek  *           while equal, change condition to !condition)
39*875abb87SDavid van Moolenbroek  *         - remove instructions loading registers from arguments (ebp+x)
40433d6423SLionel Sambuc  */
41433d6423SLionel Sambuc 
42*875abb87SDavid van Moolenbroek #include <stdio.h>
43*875abb87SDavid van Moolenbroek #include <assert.h>
44*875abb87SDavid van Moolenbroek 
45433d6423SLionel Sambuc #include "ddb.h"
46433d6423SLionel Sambuc #include "db_sym.h"
47433d6423SLionel Sambuc #include "swifi.h"
48433d6423SLionel Sambuc 
49433d6423SLionel Sambuc #include "extra.h"
50433d6423SLionel Sambuc 
51*875abb87SDavid van Moolenbroek #define PDEBUG(args) /* (printf args) */
52*875abb87SDavid van Moolenbroek 
53433d6423SLionel Sambuc #define NOP		0x90
54433d6423SLionel Sambuc 
55*875abb87SDavid van Moolenbroek static int text_fault(int type, unsigned long btext, unsigned long text_size);
56433d6423SLionel Sambuc 
57*875abb87SDavid van Moolenbroek static int randomFaults[] = {
58*875abb87SDavid van Moolenbroek   TEXT_FAULT,
59*875abb87SDavid van Moolenbroek   NOP_FAULT,
60*875abb87SDavid van Moolenbroek   SRC_FAULT,
61*875abb87SDavid van Moolenbroek   DST_FAULT,
62*875abb87SDavid van Moolenbroek   PTR_FAULT,
63*875abb87SDavid van Moolenbroek   LOOP_FAULT,
64*875abb87SDavid van Moolenbroek   INTERFACE_FAULT
65*875abb87SDavid van Moolenbroek };
66433d6423SLionel Sambuc 
67*875abb87SDavid van Moolenbroek void
swifi_inject_fault(char * module_name,unsigned long faultType,unsigned long randomSeed,unsigned long numFaults)68*875abb87SDavid van Moolenbroek swifi_inject_fault(char * module_name,
69*875abb87SDavid van Moolenbroek 		 unsigned long faultType,
70*875abb87SDavid van Moolenbroek 		 unsigned long randomSeed,
71*875abb87SDavid van Moolenbroek 		 unsigned long numFaults)
72433d6423SLionel Sambuc {
73*875abb87SDavid van Moolenbroek   unsigned long btext, etext, text_size;
74*875abb87SDavid van Moolenbroek   int type;
75433d6423SLionel Sambuc 
76433d6423SLionel Sambuc   /* default number of faults is 5 */
77*875abb87SDavid van Moolenbroek   if (numFaults == 0) numFaults = 5;
78433d6423SLionel Sambuc 
79*875abb87SDavid van Moolenbroek   srandom(randomSeed);
80433d6423SLionel Sambuc 
81*875abb87SDavid van Moolenbroek   load_nlist(module_name, &btext, &etext);
82433d6423SLionel Sambuc 
83433d6423SLionel Sambuc   text_size = etext - btext;
84433d6423SLionel Sambuc 
85433d6423SLionel Sambuc   PDEBUG(("text=%lx-%lx, size=%lx\n", btext, etext, text_size));
86433d6423SLionel Sambuc 
87*875abb87SDavid van Moolenbroek   while (numFaults) {
88*875abb87SDavid van Moolenbroek     if ((type = faultType) == RANDOM_FAULT)
89*875abb87SDavid van Moolenbroek       type = randomFaults[random() %
90*875abb87SDavid van Moolenbroek         (sizeof(randomFaults) / sizeof(randomFaults[0]))];
91*875abb87SDavid van Moolenbroek 
92*875abb87SDavid van Moolenbroek     if (text_fault(type, btext, text_size))
93*875abb87SDavid van Moolenbroek       numFaults--;
94*875abb87SDavid van Moolenbroek   }
95*875abb87SDavid van Moolenbroek }
96*875abb87SDavid van Moolenbroek 
text_fault(int type,unsigned long btext,unsigned long text_size)97*875abb87SDavid van Moolenbroek static int text_fault(int type, unsigned long btext, unsigned long text_size)
98*875abb87SDavid van Moolenbroek {
99*875abb87SDavid van Moolenbroek   unsigned long *addr, taddr;
100*875abb87SDavid van Moolenbroek   int j, flip_bit, len, prefix;
101*875abb87SDavid van Moolenbroek   unsigned char *c;
102*875abb87SDavid van Moolenbroek 
103*875abb87SDavid van Moolenbroek   /* inject faults into text space */
104*875abb87SDavid van Moolenbroek 
105433d6423SLionel Sambuc   addr = (unsigned long *)
106433d6423SLionel Sambuc     (btext + ((unsigned long) (random()&~0xf) % text_size));
107433d6423SLionel Sambuc 
108433d6423SLionel Sambuc   /* now the tricky part */
109433d6423SLionel Sambuc 
110433d6423SLionel Sambuc   taddr=(unsigned long) addr;
111*875abb87SDavid van Moolenbroek   if (type != TEXT_FAULT) {
112*875abb87SDavid van Moolenbroek     addr = (unsigned long *) find_faulty_instr(taddr, type, &len);
113433d6423SLionel Sambuc     /* do it over again if we can't find the right instruction */
114*875abb87SDavid van Moolenbroek     if (!addr || !len)
115*875abb87SDavid van Moolenbroek       return FALSE;
116433d6423SLionel Sambuc   }
117433d6423SLionel Sambuc 
118433d6423SLionel Sambuc   PDEBUG(("target addr=%lx, instr addr=%p, %lx=>", taddr, addr,
119433d6423SLionel Sambuc     text_read_ul(addr)));
120433d6423SLionel Sambuc 
121*875abb87SDavid van Moolenbroek   switch (type) {
122*875abb87SDavid van Moolenbroek   case TEXT_FAULT:
123433d6423SLionel Sambuc     flip_bit = random() & 0x1f;
124433d6423SLionel Sambuc     PDEBUG(("flip bit %d => ", flip_bit));
125433d6423SLionel Sambuc     flip_bit = 1 << flip_bit;
126433d6423SLionel Sambuc 
127433d6423SLionel Sambuc     text_write_ul(addr, text_read_ul(addr)^flip_bit);
128433d6423SLionel Sambuc 
129*875abb87SDavid van Moolenbroek     break;
130*875abb87SDavid van Moolenbroek 
131*875abb87SDavid van Moolenbroek   case NOP_FAULT:
132*875abb87SDavid van Moolenbroek   case INIT_FAULT:
133*875abb87SDavid van Moolenbroek   case BRANCH_FAULT:
134*875abb87SDavid van Moolenbroek   case INTERFACE_FAULT:
135*875abb87SDavid van Moolenbroek   case IRQ_FAULT:
136433d6423SLionel Sambuc     c = (unsigned char *) addr;
137433d6423SLionel Sambuc 
138433d6423SLionel Sambuc     for (j = 0; j < len; j++) {
139433d6423SLionel Sambuc       /* replace these bytes with NOP (*c=NOP) */
140433d6423SLionel Sambuc       text_write_ub(c, NOP);
141433d6423SLionel Sambuc 
142433d6423SLionel Sambuc       c++;
143433d6423SLionel Sambuc     }
144*875abb87SDavid van Moolenbroek 
145*875abb87SDavid van Moolenbroek     break;
146*875abb87SDavid van Moolenbroek 
147*875abb87SDavid van Moolenbroek   case DST_FAULT:
148*875abb87SDavid van Moolenbroek   case SRC_FAULT:
149433d6423SLionel Sambuc     /* skip thru the prefix and opcode, and flip bits in following bytes */
150433d6423SLionel Sambuc     c=(unsigned char *) addr;
151433d6423SLionel Sambuc     do {
152433d6423SLionel Sambuc       switch (text_read_ub(c)) {
153433d6423SLionel Sambuc       case 0x66: case 0x67: case 0x26: case 0x36:
154433d6423SLionel Sambuc       case 0x2e: case 0x3e: case 0x64: case 0x65:
155433d6423SLionel Sambuc       case 0xf0: case 0xf2: case 0xf3:
156433d6423SLionel Sambuc         prefix = 1;
157433d6423SLionel Sambuc         break;
158433d6423SLionel Sambuc       default:
159433d6423SLionel Sambuc         prefix = 0;
160433d6423SLionel Sambuc         break;
161433d6423SLionel Sambuc       }
162433d6423SLionel Sambuc       if (prefix) {
163433d6423SLionel Sambuc         c++;
164433d6423SLionel Sambuc       }
165433d6423SLionel Sambuc     } while (prefix);
166433d6423SLionel Sambuc     if(text_read_ub(c)>=0xd8 && text_read_ub(c)<=0xdf) {
167433d6423SLionel Sambuc       /* don't mess with fp instruction, yet */
168433d6423SLionel Sambuc       PDEBUG(("floating point instruction, bailing out\n"));
169*875abb87SDavid van Moolenbroek       return FALSE;
170*875abb87SDavid van Moolenbroek     }
171*875abb87SDavid van Moolenbroek     if(text_read_ub(c)==0x0f) {
172*875abb87SDavid van Moolenbroek       c++;
173*875abb87SDavid van Moolenbroek     }
174*875abb87SDavid van Moolenbroek     if(text_read_ub(c)==0x0f) {
175*875abb87SDavid van Moolenbroek       c++;
176*875abb87SDavid van Moolenbroek     }
177*875abb87SDavid van Moolenbroek     c++;
178*875abb87SDavid van Moolenbroek     len = len-((long) c - (long) addr);
179*875abb87SDavid van Moolenbroek     if (len == 0)
180*875abb87SDavid van Moolenbroek     {
181*875abb87SDavid van Moolenbroek       PDEBUG(("text_fault: len = %d\n", len));
182*875abb87SDavid van Moolenbroek       return FALSE;
183*875abb87SDavid van Moolenbroek     }
184*875abb87SDavid van Moolenbroek     flip_bit = random() % (len*8);
185*875abb87SDavid van Moolenbroek     PDEBUG(("flip bit %d (len=%d) => ", flip_bit, len));
186*875abb87SDavid van Moolenbroek     for(j=0; j<len; j++) {
187*875abb87SDavid van Moolenbroek       /* go to the right byte */
188*875abb87SDavid van Moolenbroek       if(flip_bit<8) {
189*875abb87SDavid van Moolenbroek         flip_bit = 1 << flip_bit;
190*875abb87SDavid van Moolenbroek 
191*875abb87SDavid van Moolenbroek         text_write_ub(c, (text_read_ub(c)^flip_bit));
192*875abb87SDavid van Moolenbroek 
193*875abb87SDavid van Moolenbroek         j=len;
194*875abb87SDavid van Moolenbroek       }
195*875abb87SDavid van Moolenbroek       c++;
196*875abb87SDavid van Moolenbroek       flip_bit = flip_bit-8;
197*875abb87SDavid van Moolenbroek     }
198*875abb87SDavid van Moolenbroek 
199*875abb87SDavid van Moolenbroek     break;
200*875abb87SDavid van Moolenbroek 
201*875abb87SDavid van Moolenbroek   case PTR_FAULT:
202*875abb87SDavid van Moolenbroek     /* 5f) ptr: if instruction has regmodrm byte (i_has_modrm),
203*875abb87SDavid van Moolenbroek      *     flip 1 bit in lower byte (0x0f) or any bit in following
204*875abb87SDavid van Moolenbroek      *     bytes (sib, imm or disp).
205*875abb87SDavid van Moolenbroek      */
206*875abb87SDavid van Moolenbroek     c=(unsigned char *) addr;
207*875abb87SDavid van Moolenbroek     do {
208*875abb87SDavid van Moolenbroek       switch (text_read_ub(c)) {
209*875abb87SDavid van Moolenbroek       case 0x66: case 0x67: case 0x26: case 0x36:
210*875abb87SDavid van Moolenbroek       case 0x2e: case 0x3e: case 0x64: case 0x65:
211*875abb87SDavid van Moolenbroek       case 0xf0: case 0xf2: case 0xf3:
212*875abb87SDavid van Moolenbroek         prefix = 1;
213*875abb87SDavid van Moolenbroek         break;
214*875abb87SDavid van Moolenbroek       default:
215*875abb87SDavid van Moolenbroek         prefix = 0;
216*875abb87SDavid van Moolenbroek         break;
217*875abb87SDavid van Moolenbroek       }
218*875abb87SDavid van Moolenbroek       if (prefix) {
219*875abb87SDavid van Moolenbroek         c++;
220*875abb87SDavid van Moolenbroek       }
221*875abb87SDavid van Moolenbroek     } while (prefix);
222*875abb87SDavid van Moolenbroek     if(text_read_ub(c)>=0xd8 && text_read_ub(c)<=0xdf) {
223*875abb87SDavid van Moolenbroek       /* don't mess with fp instruction, yet */
224*875abb87SDavid van Moolenbroek       PDEBUG(("floating point instruction, bailing out\n"));
225*875abb87SDavid van Moolenbroek       return FALSE;
226*875abb87SDavid van Moolenbroek     }
227*875abb87SDavid van Moolenbroek     if(text_read_ub(c)==0x0f) {
228433d6423SLionel Sambuc       c++;
229433d6423SLionel Sambuc     }
230433d6423SLionel Sambuc     if(text_read_ub(c)==0x0f) {
231433d6423SLionel Sambuc       c++;
232433d6423SLionel Sambuc     }
233433d6423SLionel Sambuc     c++;
234433d6423SLionel Sambuc     len = len-((long) c - (long) addr);
235433d6423SLionel Sambuc     flip_bit = random() % (len*8-4);
236433d6423SLionel Sambuc     PDEBUG(("flip bit %d (len=%d) => ", flip_bit, len));
237433d6423SLionel Sambuc 
238433d6423SLionel Sambuc     /* mod/rm byte is special */
239433d6423SLionel Sambuc 
240433d6423SLionel Sambuc     if (flip_bit < 4) {
241433d6423SLionel Sambuc       flip_bit = 1 << flip_bit;
242433d6423SLionel Sambuc 
243433d6423SLionel Sambuc       text_write_ub(c, text_read_ub(c)^flip_bit);
244433d6423SLionel Sambuc     }
245433d6423SLionel Sambuc     c++;
246433d6423SLionel Sambuc     flip_bit=flip_bit-4;
247433d6423SLionel Sambuc 
248433d6423SLionel Sambuc     for(j=1; j<len; j++) {
249433d6423SLionel Sambuc       /* go to the right byte */
250433d6423SLionel Sambuc       if (flip_bit<8) {
251433d6423SLionel Sambuc         flip_bit = 1 << flip_bit;
252433d6423SLionel Sambuc 
253433d6423SLionel Sambuc         text_write_ub(c, text_read_ub(c)^flip_bit);
254433d6423SLionel Sambuc 
255433d6423SLionel Sambuc         j=len;
256433d6423SLionel Sambuc       }
257433d6423SLionel Sambuc       c++;
258433d6423SLionel Sambuc       flip_bit = flip_bit-8;
259433d6423SLionel Sambuc     }
260*875abb87SDavid van Moolenbroek 
261*875abb87SDavid van Moolenbroek     break;
262*875abb87SDavid van Moolenbroek 
263*875abb87SDavid van Moolenbroek   case LOOP_FAULT:
264433d6423SLionel Sambuc     c=(unsigned char *) addr;
265433d6423SLionel Sambuc     /* replace rep with repe, and vice versa */
266433d6423SLionel Sambuc     if(text_read_ub(c)==0xf3) {
267433d6423SLionel Sambuc       text_write_ub(c, 0xf2);
268433d6423SLionel Sambuc     } else if(text_read_ub(c)==0xf2) {
269433d6423SLionel Sambuc       text_write_ub(c, 0xf3);
270433d6423SLionel Sambuc     } else if( (text_read_ub(c)&0xf0)==0x70 ) {
271433d6423SLionel Sambuc       /* if we've jxx imm8 instruction,
272433d6423SLionel Sambuc        * incl even byte instruction, eg jo (70) to jno (71)
273433d6423SLionel Sambuc        * decl odd byte instruction,  eg jnle (7f) to jle (7e)
274433d6423SLionel Sambuc        */
275433d6423SLionel Sambuc       if(text_read_ub(c)%2 == 0) {
276433d6423SLionel Sambuc                text_write_ub(c, text_read_ub(c)+1);
277433d6423SLionel Sambuc       } else {
278433d6423SLionel Sambuc         text_write_ub(c, text_read_ub(c)-1);
279433d6423SLionel Sambuc       }
280433d6423SLionel Sambuc     } else if(text_read_ub(c)==0x66 || text_read_ub(c)==0x67) {
281433d6423SLionel Sambuc 	    /* override prefix */
282433d6423SLionel Sambuc       c++;
283433d6423SLionel Sambuc     } else if(text_read_ub(c++)==0xf && (text_read_ub(c)&0xf0)==0x80 ) {
284433d6423SLionel Sambuc       /* if we've jxx imm16/32 instruction,
285433d6423SLionel Sambuc        * incl even byte instruction, eg jo (80) to jno (81)
286433d6423SLionel Sambuc        * decl odd byte instruction,  eg jnle (8f) to jle (8e)
287433d6423SLionel Sambuc        */
288433d6423SLionel Sambuc       if(text_read_ub(c)%2 == 0) {
289433d6423SLionel Sambuc         text_write_ub(c, text_read_ub(c)+1);
290433d6423SLionel Sambuc       } else {
291433d6423SLionel Sambuc         text_write_ub(c, text_read_ub(c)-1);
292433d6423SLionel Sambuc       }
293433d6423SLionel Sambuc     }
294*875abb87SDavid van Moolenbroek 
295*875abb87SDavid van Moolenbroek     break;
296*875abb87SDavid van Moolenbroek 
297*875abb87SDavid van Moolenbroek   case STOP_FAULT:
298*875abb87SDavid van Moolenbroek     text_write_ub(addr, BKPT_INST);
299*875abb87SDavid van Moolenbroek 
300*875abb87SDavid van Moolenbroek     break;
301*875abb87SDavid van Moolenbroek 
302*875abb87SDavid van Moolenbroek   default:
303*875abb87SDavid van Moolenbroek     assert(0);
304433d6423SLionel Sambuc   }
305433d6423SLionel Sambuc 
306*875abb87SDavid van Moolenbroek   return TRUE;
307433d6423SLionel Sambuc }
308