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