2008-10-02 15:43:32 +02:00
|
|
|
/*
|
|
|
|
* fault-model.c -- fault injection code for drivers
|
|
|
|
*
|
|
|
|
* Copyright (C) 2003 Mike Swift
|
|
|
|
* Copyright (c) 1999 Wee Teck Ng
|
|
|
|
*
|
|
|
|
* The source code in this file can be freely used, adapted,
|
|
|
|
* and redistributed in source or binary form, so long as an
|
2012-10-02 17:49:23 +02:00
|
|
|
* acknowledgment appears in derived source files. No warranty
|
|
|
|
* is attached; we cannot take responsibility for errors or
|
2008-10-02 15:43:32 +02:00
|
|
|
* fitness for use.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fault injector for testing the usefulness of NOOKS
|
2012-10-02 17:49:23 +02:00
|
|
|
*
|
2008-10-02 15:43:32 +02:00
|
|
|
* Adapted from the SWIFI tools used by Wee Teck Ng to evaluate the RIO
|
|
|
|
* file cache at the University of Michigan
|
2012-10-02 17:49:23 +02:00
|
|
|
*
|
2008-10-02 15:43:32 +02:00
|
|
|
*/
|
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
/*
|
|
|
|
* This tool can inject faults into modules, whether they are loaded into a
|
2008-10-02 15:43:32 +02:00
|
|
|
* nook or loaded into the kernel (for comparison testing).
|
2012-10-02 17:49:23 +02:00
|
|
|
*
|
2008-10-02 15:43:32 +02:00
|
|
|
* There are several classes of faults emulated:
|
|
|
|
* - Corruption of text
|
|
|
|
* - corruption
|
|
|
|
* - simulated programming faults
|
|
|
|
* - skip initialization (immediate write to EBP-x)
|
|
|
|
* - remove instruction (replace with NOP)
|
|
|
|
* - incorrect source/destination (corrupted)
|
|
|
|
* - remove jmp or rep instruction
|
|
|
|
* - change address computation for memory access (not stack)
|
2012-10-02 17:49:23 +02:00
|
|
|
* - change termination condition for loop (change repeat to repeat
|
|
|
|
* while equal, change condition to !condition)
|
|
|
|
* - remove instructions loading registers from arguments (ebp+x)
|
2008-10-02 15:43:32 +02:00
|
|
|
*/
|
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
2008-10-02 15:43:32 +02:00
|
|
|
#include "ddb.h"
|
|
|
|
#include "db_sym.h"
|
|
|
|
#include "swifi.h"
|
|
|
|
|
2008-10-02 15:45:46 +02:00
|
|
|
#include "extra.h"
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2008-10-02 15:45:46 +02:00
|
|
|
#define PDEBUG(args) /* (printf args) */
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
#define NOP 0x90
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
static int text_fault(int type, unsigned long btext, unsigned long text_size);
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
static int randomFaults[] = {
|
|
|
|
TEXT_FAULT,
|
|
|
|
NOP_FAULT,
|
|
|
|
SRC_FAULT,
|
|
|
|
DST_FAULT,
|
|
|
|
PTR_FAULT,
|
|
|
|
LOOP_FAULT,
|
|
|
|
INTERFACE_FAULT
|
|
|
|
};
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
void
|
|
|
|
swifi_inject_fault(char * module_name,
|
|
|
|
unsigned long faultType,
|
|
|
|
unsigned long randomSeed,
|
|
|
|
unsigned long numFaults)
|
2008-10-02 15:43:32 +02:00
|
|
|
{
|
2012-10-02 17:49:23 +02:00
|
|
|
unsigned long btext, etext, text_size;
|
|
|
|
int type;
|
2008-10-02 15:43:32 +02:00
|
|
|
|
|
|
|
/* default number of faults is 5 */
|
2012-10-02 17:49:23 +02:00
|
|
|
if (numFaults == 0) numFaults = 5;
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
srandom(randomSeed);
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
load_nlist(module_name, &btext, &etext);
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
text_size = etext - btext;
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
PDEBUG(("text=%lx-%lx, size=%lx\n", btext, etext, text_size));
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
while (numFaults) {
|
|
|
|
if ((type = faultType) == RANDOM_FAULT)
|
|
|
|
type = randomFaults[random() %
|
|
|
|
(sizeof(randomFaults) / sizeof(randomFaults[0]))];
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
if (text_fault(type, btext, text_size))
|
|
|
|
numFaults--;
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
static int text_fault(int type, unsigned long btext, unsigned long text_size)
|
2008-10-02 15:43:32 +02:00
|
|
|
{
|
2012-10-02 17:49:23 +02:00
|
|
|
unsigned long *addr, taddr;
|
|
|
|
int j, flip_bit, len, prefix;
|
|
|
|
unsigned char *c;
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
/* inject faults into text space */
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
addr = (unsigned long *)
|
|
|
|
(btext + ((unsigned long) (random()&~0xf) % text_size));
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
/* now the tricky part */
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
taddr=(unsigned long) addr;
|
|
|
|
if (type != TEXT_FAULT) {
|
|
|
|
addr = (unsigned long *) find_faulty_instr(taddr, type, &len);
|
|
|
|
/* do it over again if we can't find the right instruction */
|
|
|
|
if (!addr || !len)
|
|
|
|
return FALSE;
|
|
|
|
}
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
PDEBUG(("target addr=%lx, instr addr=%p, %lx=>", taddr, addr,
|
|
|
|
text_read_ul(addr)));
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
switch (type) {
|
|
|
|
case TEXT_FAULT:
|
2008-10-02 15:43:32 +02:00
|
|
|
flip_bit = random() & 0x1f;
|
2012-10-02 17:49:23 +02:00
|
|
|
PDEBUG(("flip bit %d => ", flip_bit));
|
2008-10-02 15:43:32 +02:00
|
|
|
flip_bit = 1 << flip_bit;
|
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
text_write_ul(addr, text_read_ul(addr)^flip_bit);
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
break;
|
2008-10-02 15:45:46 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
case NOP_FAULT:
|
|
|
|
case INIT_FAULT:
|
|
|
|
case BRANCH_FAULT:
|
|
|
|
case INTERFACE_FAULT:
|
|
|
|
case IRQ_FAULT:
|
|
|
|
c = (unsigned char *) addr;
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
for (j = 0; j < len; j++) {
|
|
|
|
/* replace these bytes with NOP (*c=NOP) */
|
|
|
|
text_write_ub(c, NOP);
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
c++;
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DST_FAULT:
|
|
|
|
case SRC_FAULT:
|
|
|
|
/* skip thru the prefix and opcode, and flip bits in following bytes */
|
|
|
|
c=(unsigned char *) addr;
|
|
|
|
do {
|
|
|
|
switch (text_read_ub(c)) {
|
|
|
|
case 0x66: case 0x67: case 0x26: case 0x36:
|
|
|
|
case 0x2e: case 0x3e: case 0x64: case 0x65:
|
|
|
|
case 0xf0: case 0xf2: case 0xf3:
|
|
|
|
prefix = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
prefix = 0;
|
|
|
|
break;
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
2012-10-02 17:49:23 +02:00
|
|
|
if (prefix) {
|
|
|
|
c++;
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
2012-10-02 17:49:23 +02:00
|
|
|
} while (prefix);
|
|
|
|
if(text_read_ub(c)>=0xd8 && text_read_ub(c)<=0xdf) {
|
|
|
|
/* don't mess with fp instruction, yet */
|
|
|
|
PDEBUG(("floating point instruction, bailing out\n"));
|
|
|
|
return FALSE;
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
2012-10-02 17:49:23 +02:00
|
|
|
if(text_read_ub(c)==0x0f) {
|
|
|
|
c++;
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
2012-10-02 17:49:23 +02:00
|
|
|
if(text_read_ub(c)==0x0f) {
|
|
|
|
c++;
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
2012-10-02 17:49:23 +02:00
|
|
|
c++;
|
|
|
|
len = len-((long) c - (long) addr);
|
|
|
|
if (len == 0)
|
|
|
|
{
|
|
|
|
PDEBUG(("text_fault: len = %d\n", len));
|
|
|
|
return FALSE;
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
2012-10-02 17:49:23 +02:00
|
|
|
flip_bit = random() % (len*8);
|
|
|
|
PDEBUG(("flip bit %d (len=%d) => ", flip_bit, len));
|
|
|
|
for(j=0; j<len; j++) {
|
|
|
|
/* go to the right byte */
|
|
|
|
if(flip_bit<8) {
|
|
|
|
flip_bit = 1 << flip_bit;
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
text_write_ub(c, (text_read_ub(c)^flip_bit));
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
j=len;
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
2012-10-02 17:49:23 +02:00
|
|
|
c++;
|
|
|
|
flip_bit = flip_bit-8;
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
break;
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
case PTR_FAULT:
|
|
|
|
/* 5f) ptr: if instruction has regmodrm byte (i_has_modrm),
|
|
|
|
* flip 1 bit in lower byte (0x0f) or any bit in following
|
|
|
|
* bytes (sib, imm or disp).
|
|
|
|
*/
|
|
|
|
c=(unsigned char *) addr;
|
|
|
|
do {
|
|
|
|
switch (text_read_ub(c)) {
|
|
|
|
case 0x66: case 0x67: case 0x26: case 0x36:
|
|
|
|
case 0x2e: case 0x3e: case 0x64: case 0x65:
|
|
|
|
case 0xf0: case 0xf2: case 0xf3:
|
|
|
|
prefix = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
prefix = 0;
|
|
|
|
break;
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
2012-10-02 17:49:23 +02:00
|
|
|
if (prefix) {
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
} while (prefix);
|
|
|
|
if(text_read_ub(c)>=0xd8 && text_read_ub(c)<=0xdf) {
|
|
|
|
/* don't mess with fp instruction, yet */
|
|
|
|
PDEBUG(("floating point instruction, bailing out\n"));
|
|
|
|
return FALSE;
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
2012-10-02 17:49:23 +02:00
|
|
|
if(text_read_ub(c)==0x0f) {
|
|
|
|
c++;
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
2012-10-02 17:49:23 +02:00
|
|
|
if(text_read_ub(c)==0x0f) {
|
|
|
|
c++;
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
2012-10-02 17:49:23 +02:00
|
|
|
c++;
|
|
|
|
len = len-((long) c - (long) addr);
|
|
|
|
flip_bit = random() % (len*8-4);
|
|
|
|
PDEBUG(("flip bit %d (len=%d) => ", flip_bit, len));
|
2008-10-02 15:45:46 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
/* mod/rm byte is special */
|
2008-10-02 15:45:46 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
if (flip_bit < 4) {
|
2008-10-02 15:43:32 +02:00
|
|
|
flip_bit = 1 << flip_bit;
|
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
text_write_ub(c, text_read_ub(c)^flip_bit);
|
|
|
|
}
|
|
|
|
c++;
|
|
|
|
flip_bit=flip_bit-4;
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
for(j=1; j<len; j++) {
|
|
|
|
/* go to the right byte */
|
|
|
|
if (flip_bit<8) {
|
|
|
|
flip_bit = 1 << flip_bit;
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
text_write_ub(c, text_read_ub(c)^flip_bit);
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
j=len;
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
|
|
|
c++;
|
2012-10-02 17:49:23 +02:00
|
|
|
flip_bit = flip_bit-8;
|
|
|
|
}
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LOOP_FAULT:
|
|
|
|
c=(unsigned char *) addr;
|
|
|
|
/* replace rep with repe, and vice versa */
|
|
|
|
if(text_read_ub(c)==0xf3) {
|
|
|
|
text_write_ub(c, 0xf2);
|
|
|
|
} else if(text_read_ub(c)==0xf2) {
|
|
|
|
text_write_ub(c, 0xf3);
|
|
|
|
} else if( (text_read_ub(c)&0xf0)==0x70 ) {
|
|
|
|
/* if we've jxx imm8 instruction,
|
|
|
|
* incl even byte instruction, eg jo (70) to jno (71)
|
|
|
|
* decl odd byte instruction, eg jnle (7f) to jle (7e)
|
2008-10-02 15:43:32 +02:00
|
|
|
*/
|
2012-10-02 17:49:23 +02:00
|
|
|
if(text_read_ub(c)%2 == 0) {
|
|
|
|
text_write_ub(c, text_read_ub(c)+1);
|
|
|
|
} else {
|
|
|
|
text_write_ub(c, text_read_ub(c)-1);
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
2012-10-02 17:49:23 +02:00
|
|
|
} else if(text_read_ub(c)==0x66 || text_read_ub(c)==0x67) {
|
|
|
|
/* override prefix */
|
2008-10-02 15:43:32 +02:00
|
|
|
c++;
|
2012-10-02 17:49:23 +02:00
|
|
|
} else if(text_read_ub(c++)==0xf && (text_read_ub(c)&0xf0)==0x80 ) {
|
|
|
|
/* if we've jxx imm16/32 instruction,
|
|
|
|
* incl even byte instruction, eg jo (80) to jno (81)
|
|
|
|
* decl odd byte instruction, eg jnle (8f) to jle (8e)
|
|
|
|
*/
|
|
|
|
if(text_read_ub(c)%2 == 0) {
|
|
|
|
text_write_ub(c, text_read_ub(c)+1);
|
|
|
|
} else {
|
|
|
|
text_write_ub(c, text_read_ub(c)-1);
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
2012-10-02 17:49:23 +02:00
|
|
|
}
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
break;
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
case STOP_FAULT:
|
|
|
|
text_write_ub(addr, BKPT_INST);
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
break;
|
2008-10-02 15:43:32 +02:00
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
default:
|
|
|
|
assert(0);
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|
|
|
|
|
2012-10-02 17:49:23 +02:00
|
|
|
return TRUE;
|
2008-10-02 15:43:32 +02:00
|
|
|
}
|