2 * fault-model.c -- fault injection code for drivers
4 * Copyright (C) 2003 Mike Swift
5 * Copyright (c) 1999 Wee Teck Ng
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
17 * Fault injector for testing the usefulness of NOOKS
19 * Adapted from the SWIFI tools used by Wee Teck Ng to evaluate the RIO
20 * file cache at the University of Michigan
25 * This tool can inject faults into modules, whether they are loaded into a
26 * nook or loaded into the kernel (for comparison testing).
28 * There are several classes of faults emulated:
29 * - Corruption of text
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)
51 #define PDEBUG(args) /* (printf args) */
55 static int text_fault(int type
, unsigned long btext
, unsigned long text_size
);
57 static int randomFaults
[] = {
68 swifi_inject_fault(char * module_name
,
69 unsigned long faultType
,
70 unsigned long randomSeed
,
71 unsigned long numFaults
)
73 unsigned long btext
, etext
, text_size
;
76 /* default number of faults is 5 */
77 if (numFaults
== 0) numFaults
= 5;
81 load_nlist(module_name
, &btext
, &etext
);
83 text_size
= etext
- btext
;
85 PDEBUG(("text=%lx-%lx, size=%lx\n", btext
, etext
, text_size
));
88 if ((type
= faultType
) == RANDOM_FAULT
)
89 type
= randomFaults
[random() %
90 (sizeof(randomFaults
) / sizeof(randomFaults
[0]))];
92 if (text_fault(type
, btext
, text_size
))
97 static int text_fault(int type
, unsigned long btext
, unsigned long text_size
)
99 unsigned long *addr
, taddr
;
100 int j
, flip_bit
, len
, prefix
;
103 /* inject faults into text space */
105 addr
= (unsigned long *)
106 (btext
+ ((unsigned long) (random()&~0xf) % text_size
));
108 /* now the tricky part */
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 */
118 PDEBUG(("target addr=%lx, instr addr=%p, %lx=>", taddr
, addr
,
119 text_read_ul(addr
)));
123 flip_bit
= random() & 0x1f;
124 PDEBUG(("flip bit %d => ", flip_bit
));
125 flip_bit
= 1 << flip_bit
;
127 text_write_ul(addr
, text_read_ul(addr
)^flip_bit
);
134 case INTERFACE_FAULT
:
136 c
= (unsigned char *) addr
;
138 for (j
= 0; j
< len
; j
++) {
139 /* replace these bytes with NOP (*c=NOP) */
140 text_write_ub(c
, NOP
);
149 /* skip thru the prefix and opcode, and flip bits in following bytes */
150 c
=(unsigned char *) addr
;
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:
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"));
171 if(text_read_ub(c
)==0x0f) {
174 if(text_read_ub(c
)==0x0f) {
178 len
= len
-((long) c
- (long) addr
);
181 PDEBUG(("text_fault: len = %d\n", len
));
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 */
189 flip_bit
= 1 << flip_bit
;
191 text_write_ub(c
, (text_read_ub(c
)^flip_bit
));
196 flip_bit
= flip_bit
-8;
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).
206 c
=(unsigned char *) addr
;
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:
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"));
227 if(text_read_ub(c
)==0x0f) {
230 if(text_read_ub(c
)==0x0f) {
234 len
= len
-((long) c
- (long) addr
);
235 flip_bit
= random() % (len
*8-4);
236 PDEBUG(("flip bit %d (len=%d) => ", flip_bit
, len
));
238 /* mod/rm byte is special */
241 flip_bit
= 1 << flip_bit
;
243 text_write_ub(c
, text_read_ub(c
)^flip_bit
);
248 for(j
=1; j
<len
; j
++) {
249 /* go to the right byte */
251 flip_bit
= 1 << flip_bit
;
253 text_write_ub(c
, text_read_ub(c
)^flip_bit
);
258 flip_bit
= flip_bit
-8;
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)
275 if(text_read_ub(c
)%2 == 0) {
276 text_write_ub(c
, text_read_ub(c
)+1);
278 text_write_ub(c
, text_read_ub(c
)-1);
280 } else if(text_read_ub(c
)==0x66 || text_read_ub(c
)==0x67) {
281 /* override prefix */
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)
288 if(text_read_ub(c
)%2 == 0) {
289 text_write_ub(c
, text_read_ub(c
)+1);
291 text_write_ub(c
, text_read_ub(c
)-1);
298 text_write_ub(addr
, BKPT_INST
);