L4Sys: adapt to DatabaseCampaign

Change-Id: Ia4912e7a74afccb51f6d704830a2d9c5b5c0159a
This commit is contained in:
Bjoern Doebel
2013-08-30 16:06:15 +02:00
parent 045c08faf6
commit 1ca9cb4a52
6 changed files with 404 additions and 330 deletions

View File

@ -37,10 +37,10 @@ add_library(fail-${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SR
find_package(LibUdis86 REQUIRED)
include_directories(${LIBUDIS86_INCLUDE_DIRS})
link_directories(${LIBUDIS86_LINK_DIRS})
add_dependencies(fail-${EXPERIMENT_NAME} fail-comm fail-tracing)
add_dependencies(fail-${EXPERIMENT_NAME} fail-comm)
target_link_libraries(fail-${EXPERIMENT_NAME} ${LIBUDIS86_LIBRARIES} ${PROTOBUF_LIBRARY})
## This is the example's campaign server distributing experiment parameters
add_executable(${EXPERIMENT_NAME}-server main.cc)
target_link_libraries(${EXPERIMENT_NAME}-server fail-${EXPERIMENT_NAME} fail ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY})
target_link_libraries(${EXPERIMENT_NAME}-server fail-${EXPERIMENT_NAME} -Wl,--start-group fail-sal fail-util fail-cpn fail-comm ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} -lmysqlclient -Wl,--end-group)
install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin)

View File

@ -4,6 +4,7 @@
#include "campaign.hpp"
#include "experimentInfo.hpp"
#include "conversion.hpp"
#include "comm/DatabaseCampaignMessage.pb.h"
#include "cpn/CampaignManager.hpp"
#include "util/Logger.hpp"
#include "sal/SALConfig.hpp"
@ -17,6 +18,7 @@ extern L4SysConversion l4sysResultConversion;
extern L4SysConversion l4sysExperimentConversion;
extern L4SysConversion l4sysRegisterConversion;
#if 0
bool L4SysCampaign::run() {
Logger log("L4SysCampaign");
@ -51,7 +53,6 @@ bool L4SysCampaign::run() {
}
}
#if 0
for (int i = 0; i < 20000; ++i) {
L4SysExperimentData *d = new L4SysExperimentData;
d->msg.set_exp_type(d->msg.GPRFLIP);
@ -106,7 +107,6 @@ bool L4SysCampaign::run() {
campaignmanager.addParam(d);
++count;
}
#endif
campaignmanager.noMoreParameters();
log << "done enqueueing parameter sets (" << count << ")." << endl;
@ -143,3 +143,21 @@ bool L4SysCampaign::run() {
return true;
}
#endif
using namespace google::protobuf;
void L4SysCampaign::cb_send_pilot(DatabaseCampaignMessage p)
{
#if 0
int inj_instr = p.injection_instr();
int data_addr = p.data_address();
int reg = (data_addr >> 8) & 0xF;
int width = (data_addr >> 4) & 0xF;
int offs = data_addr & 0xF;
#endif
L4SysExperimentData *d = new L4SysExperimentData;
d->msg.mutable_fsppilot()->CopyFrom(p);
d->msg.set_exp_type(d->msg.GPRFLIP);
campaignmanager.addParam(d);
}

View File

@ -1,9 +1,10 @@
#ifndef __L4SYS_CAMPAIGN_HPP__
#define __L4SYS_CAMPAIGN_HPP__
#define __L4SYS_CAMPAIGN_HPP__
#include "cpn/Campaign.hpp"
#include "cpn/DatabaseCampaign.hpp"
#include "comm/ExperimentData.hpp"
#include "l4sys.pb.h"
#include <google/protobuf/descriptor.h>
class L4SysExperimentData : public fail::ExperimentData {
public:
@ -11,9 +12,16 @@ public:
L4SysExperimentData() : fail::ExperimentData(&msg) {}
};
class L4SysCampaign : public fail::Campaign {
class L4SysCampaign : public fail::DatabaseCampaign {
#if 0
public:
virtual bool run();
#else
virtual const google::protobuf::Descriptor * cb_result_message()
{ return google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("L4SysProtoMsg"); }
virtual void cb_send_pilot(DatabaseCampaignMessage pilot);
#endif
};
#endif // __L4SYS_CAMPAIGN_HPP__

View File

@ -21,6 +21,7 @@
#include "config/FailConfig.hpp"
#include "util/ProtoStream.hpp"
#include "TracePlugin.pb.h"
#include "util/gzstream/gzstream.h"
#include "l4sys.pb.h"
@ -35,8 +36,7 @@ using namespace fail;
save, and restore. Enable these in the configuration.
#endif
string output;
string golden_run;
//string golden_run;
extern L4SysConversion l4sysRegisterConversion;
string L4SysExperiment::sanitised(const string &in_str) {
@ -62,13 +62,13 @@ BaseListener* L4SysExperiment::waitIOOrOther(bool clear_output) {
IOPortListener ev_ioport(0x3F8, true);
BaseListener* ev = NULL;
if (clear_output)
output.clear();
currentOutput.clear();
while (true) {
simulator.addListener(&ev_ioport);
ev = simulator.resume();
simulator.removeListener(&ev_ioport);
if (ev == &ev_ioport) {
output += ev_ioport.getData();
currentOutput += ev_ioport.getData();
} else {
break;
}
@ -112,6 +112,8 @@ bx_bool L4SysExperiment::fetchInstruction(BX_CPU_C *instance,
}
void L4SysExperiment::logInjection() {
// XXX fixme
#if 0
// explicit type assignment necessary before sending over output stream
int id = param->getWorkloadID();
int instr_offset = param->msg.instr_offset();
@ -122,9 +124,13 @@ void L4SysExperiment::logInjection() {
log << "job " << id << " exp_type " << exp_type << endl;
log << "inject @ ip " << hex << injection_ip << " (offset " << dec << instr_offset
<< ")" << " bit " << bit_offset << endl;
#endif
}
BaseListener *L4SysExperiment::singleStep(bool preserveAddressSpace) {
// XXX: fixme
return 0;
#if 0
address_t aspace = (preserveAddressSpace ? L4SYS_ADDRESS_SPACE : ANY_ADDR);
BPSingleListener singlestepping_event(ANY_ADDR, aspace);
simulator.addListener(&singlestepping_event);
@ -143,13 +149,14 @@ BaseListener *L4SysExperiment::singleStep(bool preserveAddressSpace) {
param->msg.set_resulttype(param->msg.TIMEOUT);
param->msg.set_resultdata(
simulator.getCPU(0).getInstructionPointer());
param->msg.set_output(sanitised(output.c_str()));
param->msg.set_output(sanitised(currentOutput.c_str()));
param->msg.set_details("Timed out immediately after injecting");
m_jc.sendResult(*param);
terminate(0);
}
return ev;
#endif
}
void L4SysExperiment::injectInstruction(
@ -195,11 +202,11 @@ void L4SysExperiment::terminate(int reason) {
}
void L4SysExperiment::terminateWithError(string details, int reason) {
param->msg.set_resulttype(param->msg.UNKNOWN);
param->msg.set_resultdata(
simulator.getCPU(0).getInstructionPointer());
param->msg.set_output(sanitised(output.c_str()));
param->msg.set_details(details);
L4SysProtoMsg_Result *result = param->msg.add_result();
result->set_resulttype(param->msg.UNKNOWN);
result->set_resultdata(simulator.getCPU(0).getInstructionPointer());
result->set_output(sanitised(currentOutput.c_str()));
result->set_details(details);
m_jc.sendResult(*param);
terminate(reason);
@ -237,7 +244,7 @@ void L4SysExperiment::collectInstructionTrace(fail::BPSingleListener& bp)
map<address_t, unsigned> times_called_map;
bool injecting = false;
std::ofstream out("trace.pb");
ogzstream out("trace.pb");
ProtoOStream *os = new ProtoOStream(&out);
while (bp.getTriggerInstructionPointer() != L4SYS_FUNC_EXIT) {
@ -281,6 +288,7 @@ void L4SysExperiment::collectInstructionTrace(fail::BPSingleListener& bp)
// the generic *-trace tools
// XXX: need to log CR3 if we want multiple binaries here
Trace_Event e;
e.set_time_delta(1);
e.set_ip(curr_addr);
os->writeMessage(&e);
}
@ -317,13 +325,14 @@ void L4SysExperiment::goldenRun(fail::BPSingleListener& bp)
<< simulator.getCPU(0).getInstructionPointer()
<< endl;
std::string golden_run;
ofstream golden_run_file(L4SYS_CORRECT_OUTPUT);
bp.setWatchInstructionPointer(L4SYS_FUNC_EXIT);
simulator.addListener(&bp);
BaseListener* ev = waitIOOrOther(true);
if (ev == &bp) {
golden_run.assign(output.c_str());
golden_run_file << output.c_str();
golden_run.assign(currentOutput.c_str());
golden_run_file << currentOutput.c_str();
log << "Output successfully logged!" << endl;
} else {
log
@ -364,6 +373,9 @@ bool L4SysExperiment::run() {
log << "Important data missing - call \"prepare\" first." << endl;
terminate(10);
}
// Read the golden run output for validation purposes
std::string golden_run;
ifstream golden_run_file(L4SYS_CORRECT_OUTPUT);
if (!golden_run_file.good()) {
@ -377,12 +389,7 @@ bool L4SysExperiment::run() {
golden_run_file.close();
//the generated output probably has a similar length
output.reserve(teststruct.st_size);
log << "restoring state" << endl;
simulator.restore(L4SYS_STATE_FOLDER);
// get the experiment parameters
log << "asking job server for experiment parameters" << endl;
if (!m_jc.getParam(*param)) {
log << "Dying." << endl;
@ -390,339 +397,369 @@ bool L4SysExperiment::run() {
terminate(1);
}
int instr_offset = param->msg.instr_offset();
int bit_offset = param->msg.bit_offset();
int exp_type = param->msg.exp_type();
int exp_type = param->msg.exp_type();
int instr_offset = param->msg.fsppilot().injection_instr();
int regData = param->msg.fsppilot().data_address();
log << " got job parameters: offs " << hex << instr_offset
<< " bit " << bit_offset << " exp " << exp_type << endl;
int reg, width, offset;
reg = ((regData >> 8) & 0xF) + 1; // regs start at 1
width = (regData >> 4) & 0xF;
offset = regData & 0xF;
log << "Inject type " << exp_type << " at instr. offset " << instr_offset
<< " reg data (" << reg << ", " << width << ", "
<< offset << ")" << std::endl;
/* Each experiment message stands for 8 bits to be tested */
for (unsigned bit_offset = 0; bit_offset < 8; ++bit_offset) {
//the generated output probably has a similar length
currentOutput.clear();
currentOutput.reserve(teststruct.st_size);
simulator.clearListeners();
L4SysProtoMsg_Result *result = param->msg.add_result();
result->set_instr_offset(instr_offset);
result->set_bit_offset(bit_offset + 8 * offset);
result->set_register_offset(static_cast<L4SysProtoMsg_RegisterType>(reg));
// restore experiment state
log << "restoring state" << endl;
simulator.restore(L4SYS_STATE_FOLDER);
log << "EIP = " << hex << simulator.getCPU(0).getInstructionPointer() << endl;
#ifdef L4SYS_FILTER_INSTRUCTIONS
ifstream instr_list_file(L4SYS_INSTRUCTION_LIST, ios::binary);
// XXX still needed???
ifstream instr_list_file(L4SYS_INSTRUCTION_LIST, ios::binary);
if (!instr_list_file.good()) {
log << "Missing instruction trace" << endl;
terminate(21);
}
if (!instr_list_file.good()) {
log << "Missing instruction trace" << endl;
terminate(21);
}
TraceInstr curr_instr;
instr_list_file.seekg(instr_offset * sizeof(TraceInstr));
log << instr_list_file.eof() << " " << instr_list_file.bad() << " "
<< instr_list_file.fail() << endl;
if (instr_list_file.eof()) {
log << "Job parameters indicate position outside the traced instruction list." << endl;
terminate(1);
}
instr_list_file.read(reinterpret_cast<char*>(&curr_instr), sizeof(TraceInstr));
instr_list_file.close();
TraceInstr curr_instr;
instr_list_file.seekg(instr_offset * sizeof(TraceInstr));
log << instr_list_file.eof() << " " << instr_list_file.bad() << " "
<< instr_list_file.fail() << endl;
if (instr_list_file.eof()) {
log << "Job parameters indicate position outside the traced instruction list." << endl;
terminate(1);
}
instr_list_file.read(reinterpret_cast<char*>(&curr_instr), sizeof(TraceInstr));
instr_list_file.close();
log << "setting watchpoint at " << hex << curr_instr.trigger_addr << endl;
bp.setWatchInstructionPointer(curr_instr.trigger_addr);
log << "setting bp counter " << hex << curr_instr.bp_counter << endl;
bp.setCounter(curr_instr.bp_counter);
log << "setting watchpoint at " << hex << curr_instr.trigger_addr << endl;
bp.setWatchInstructionPointer(curr_instr.trigger_addr);
log << "setting bp counter " << hex << curr_instr.bp_counter << endl;
bp.setCounter(curr_instr.bp_counter);
#else
bp.setWatchInstructionPointer(ANY_ADDR);
bp.setCounter(instr_offset);
bp.setWatchInstructionPointer(ANY_ADDR);
bp.setCounter(instr_offset);
#endif
simulator.addListener(&bp);
//and log the output
waitIOOrOther(true);
simulator.addListener(&bp);
//and log the output
waitIOOrOther(true);
// note at what IP we will do the injection
address_t injection_ip =
// note at what IP we will do the injection
address_t testIP = param->msg.fsppilot().injection_instr_absolute() & 0xFFFFFFFF;
address_t injection_ip =
simulator.getCPU(0).getInstructionPointer();
param->msg.set_injection_ip(injection_ip);
result->set_injection_ip(injection_ip);
log << std::hex << "testIP " << testIP << " <-> " << injection_ip
<< " inject_ip_abs" << std::endl;
if (testIP != injection_ip) {
stringstream ss;
ss << std::hex << "Test IP " << testIP << " does not match injection IP "
<< injection_ip << std::endl;
terminateWithError(ss.str(), 19);
}
#ifdef L4SYS_FILTER_INSTRUCTIONS
// only works if we filter instructions
// sanity check (only works if we're working with an instruction trace)
if (injection_ip != curr_instr.trigger_addr) {
stringstream ss;
ss << "SANITY CHECK FAILED: " << injection_ip << " != "
<< curr_instr.trigger_addr;
log << ss.str() << endl;
terminateWithError(ss.str(), 20);
}
// only works if we filter instructions
// sanity check (only works if we're working with an instruction trace)
if (injection_ip != curr_instr.trigger_addr) {
stringstream ss;
ss << "SANITY CHECK FAILED: " << injection_ip << " != "
<< curr_instr.trigger_addr;
log << ss.str() << endl;
terminateWithError(ss.str(), 20);
}
#endif
// inject
if (exp_type == param->msg.GPRFLIP) {
if (!param->msg.has_register_offset()) {
terminateWithError(
"Sent package did not contain the injection location (register offset)",
30);
}
int reg_offset = param->msg.register_offset();
ConcreteCPU& cpu = simulator.getCPU(0);
Register *reg_target = cpu.getRegister(reg_offset - 1);
regdata_t data = cpu.getRegisterContent(reg_target);
regdata_t newdata = data ^ (1 << bit_offset);
cpu.setRegisterContent(reg_target, newdata);
// inject
if (exp_type == param->msg.GPRFLIP) {
int reg_offset = reg; // XXX redundant
ConcreteCPU& cpu = simulator.getCPU(0);
Register *reg_target = cpu.getRegister(reg_offset - 1);
regdata_t data = cpu.getRegisterContent(reg_target);
regdata_t newdata = data ^ (1 << (bit_offset + 8 * offset));
cpu.setRegisterContent(reg_target, newdata);
// do the logging in case everything worked out
logInjection();
log << "IP " << hex << simulator.getCPU(0).getInstructionPointer()
<< " register data: 0x" << hex << ((int) data) << " -> 0x"
<< ((int) newdata) << endl;
} else if (exp_type == param->msg.IDCFLIP) {
// this is a twisted one
// do the logging in case everything worked out
logInjection();
log << "IP " << hex << simulator.getCPU(0).getInstructionPointer()
<< " register data: 0x" << hex << ((int) data) << " -> 0x"
<< ((int) newdata) << endl;
}
// XXX: Fixme to work with database campaign!
#if 0
else if (exp_type == param->msg.IDCFLIP) {
// this is a twisted one
// initial definitions
bxInstruction_c *currInstr = simulator.getCurrentInstruction();
unsigned length_in_bits = currInstr->ilen() << 3;
// get the instruction in plain text and inject the error there
// Note: we need to fetch some extra bytes into the array
// in case the faulty instruction is interpreted to be longer
// than the original one
Bit8u curr_instr_plain[MAX_INSTR_BYTES];
const Bit8u *addr = calculateInstructionAddress();
memcpy(curr_instr_plain, addr, MAX_INSTR_BYTES);
// CampaignManager has no idea of the instruction length
// (neither do we), therefore this small adaption
bit_offset %= length_in_bits;
param->msg.set_bit_offset(bit_offset);
// do some access calculation
int byte_index = bit_offset >> 3;
Bit8u bit_index = bit_offset & 7;
// apply the fault
curr_instr_plain[byte_index] ^= 0x80 >> bit_index;
// decode the instruction
bxInstruction_c bochs_instr;
memset(&bochs_instr, 0, sizeof(bxInstruction_c));
fetchInstruction(simulator.getCPUContext(), curr_instr_plain,
&bochs_instr);
// inject it
injectInstruction(currInstr, &bochs_instr);
// do the logging
logInjection();
} else if (exp_type == param->msg.RATFLIP) {
ud_type_t which = UD_NONE;
unsigned rnd = 0;
Udis86 udis(injection_ip);
do {
// initial definitions
bxInstruction_c *currInstr = simulator.getCurrentInstruction();
udis.setInputBuffer(calculateInstructionAddress(), currInstr->ilen());
if (!udis.fetchNextInstruction()) {
terminateWithError(
"Could not decode instruction using UDIS86", 32);
}
ud_t _ud = udis.getCurrentState();
unsigned length_in_bits = currInstr->ilen() << 3;
/* start Bjoern Doebel's code (slightly modified) */
/* ============================================== */
unsigned opcount = 0;
unsigned operands[4] = { ~0U, ~0U, ~0U, ~0U };
enum {
RAT_IDX_MASK = 0x0FF,
RAT_IDX_OFFSET = 0x100
};
// get the instruction in plain text and inject the error there
// Note: we need to fetch some extra bytes into the array
// in case the faulty instruction is interpreted to be longer
// than the original one
Bit8u curr_instr_plain[MAX_INSTR_BYTES];
const Bit8u *addr = calculateInstructionAddress();
memcpy(curr_instr_plain, addr, MAX_INSTR_BYTES);
for (unsigned i = 0; i < 3; ++i) {
/*
* Case 1: operand is a register
*/
if (_ud.operand[i].type == UD_OP_REG) {
operands[opcount++] = i;
} else if (_ud.operand[i].type == UD_OP_MEM) {
// CampaignManager has no idea of the instruction length
// (neither do we), therefore this small adaption
bit_offset %= length_in_bits;
param->msg.set_bit_offset(bit_offset);
// do some access calculation
int byte_index = bit_offset >> 3;
Bit8u bit_index = bit_offset & 7;
// apply the fault
curr_instr_plain[byte_index] ^= 0x80 >> bit_index;
// decode the instruction
bxInstruction_c bochs_instr;
memset(&bochs_instr, 0, sizeof(bxInstruction_c));
fetchInstruction(simulator.getCPUContext(), curr_instr_plain,
&bochs_instr);
// inject it
injectInstruction(currInstr, &bochs_instr);
// do the logging
logInjection();
} else if (exp_type == param->msg.RATFLIP) {
ud_type_t which = UD_NONE;
unsigned rnd = 0;
Udis86 udis(injection_ip);
do {
bxInstruction_c *currInstr = simulator.getCurrentInstruction();
udis.setInputBuffer(calculateInstructionAddress(), currInstr->ilen());
if (!udis.fetchNextInstruction()) {
terminateWithError(
"Could not decode instruction using UDIS86", 32);
}
ud_t _ud = udis.getCurrentState();
/* start Bjoern Doebel's code (slightly modified) */
/* ============================================== */
unsigned opcount = 0;
unsigned operands[4] = { ~0U, ~0U, ~0U, ~0U };
enum {
RAT_IDX_MASK = 0x0FF,
RAT_IDX_OFFSET = 0x100
};
for (unsigned i = 0; i < 3; ++i) {
/*
* Case 2: operand is memory op.
*
* In this case, we may have 2 registers involved for the
* index-scale address calculation.
* Case 1: operand is a register
*/
if (_ud.operand[i].base != 0) // 0 if hard-wired mem operand
if (_ud.operand[i].type == UD_OP_REG) {
operands[opcount++] = i;
if (_ud.operand[i].index != 0)
operands[opcount++] = i + RAT_IDX_OFFSET;
} else if (_ud.operand[i].type == UD_OP_MEM) {
/*
* Case 2: operand is memory op.
*
* In this case, we may have 2 registers involved for the
* index-scale address calculation.
*/
if (_ud.operand[i].base != 0) // 0 if hard-wired mem operand
operands[opcount++] = i;
if (_ud.operand[i].index != 0)
operands[opcount++] = i + RAT_IDX_OFFSET;
}
}
}
if (opcount == 0) {
// try the next instruction
singleStep(true);
} else {
// assign the necessary variables
rnd = rand() % opcount;
if (operands[rnd] > RAT_IDX_OFFSET) {
which = _ud.operand[operands[rnd] - RAT_IDX_OFFSET].index;
if (opcount == 0) {
// try the next instruction
singleStep(true);
} else {
which = _ud.operand[operands[rnd]].base;
// assign the necessary variables
rnd = rand() % opcount;
if (operands[rnd] > RAT_IDX_OFFSET) {
which = _ud.operand[operands[rnd] - RAT_IDX_OFFSET].index;
} else {
which = _ud.operand[operands[rnd]].base;
}
}
}
/* ============================================ */
/* end Bjoern Doebel's code (slightly modified) */
/* ============================================ */
/* end Bjoern Doebel's code (slightly modified) */
} while (which == UD_NONE &&
simulator.getCPU(0).getInstructionPointer() != L4SYS_FUNC_EXIT);
} while (which == UD_NONE &&
simulator.getCPU(0).getInstructionPointer() != L4SYS_FUNC_EXIT);
if (simulator.getCPU(0).getInstructionPointer() == L4SYS_FUNC_EXIT) {
stringstream ss;
ss << "Reached the end of the experiment ";
ss << "without finding an appropriate instruction";
terminateWithError(ss.str(), 33);
}
// store the real injection point
param->msg.set_injection_ip(simulator.getCPU(0).getInstructionPointer());
// so we are able to flip the associated registers
// for details on the algorithm, see Bjoern Doebel's SWIFI/RATFlip class
// some declarations
GPRegisterId bochs_reg = Udis86::udisGPRToFailBochsGPR(which);
param->msg.set_register_offset(
static_cast<L4SysProtoMsg_RegisterType>(bochs_reg + 1));
ConcreteCPU &cpu = simulator.getCPU(0);
Register *bochsRegister = cpu.getRegister(bochs_reg);
Register *exchangeRegister = NULL;
// first, decide if the fault hits a register bound to this thread
// (ten percent chance)
if (rand() % 10 == 0) {
// assure exchange of registers
unsigned int exchg_reg = rand() % 7;
if (exchg_reg == bochs_reg)
exchg_reg++;
exchangeRegister = cpu.getRegister(exchg_reg);
param->msg.set_details(l4sysRegisterConversion.output(exchg_reg + 1));
}
// prepare the fault
regdata_t data = cpu.getRegisterContent(bochsRegister);
if (rnd > 0) {
//input register - do the fault injection here
regdata_t newdata = 0;
if (exchangeRegister != NULL) {
// the data is taken from a process register chosen before
newdata = cpu.getRegisterContent(exchangeRegister);
} else {
// the data comes from an uninitialised register
newdata = rand();
if (simulator.getCPU(0).getInstructionPointer() == L4SYS_FUNC_EXIT) {
stringstream ss;
ss << "0x" << hex << newdata;
param->msg.set_details(ss.str());
ss << "Reached the end of the experiment ";
ss << "without finding an appropriate instruction";
terminateWithError(ss.str(), 33);
}
cpu.setRegisterContent(bochsRegister, newdata);
}
// execute the instruction
singleStep(true);
// store the real injection point
param->msg.set_injection_ip(simulator.getCPU(0).getInstructionPointer());
// restore the register if we are still in the thread
if (rnd == 0) {
// output register - do the fault injection here
if (exchangeRegister != NULL) {
// write the result into the wrong local register
regdata_t newdata = cpu.getRegisterContent(bochsRegister);
cpu.setRegisterContent(exchangeRegister, newdata);
// so we are able to flip the associated registers
// for details on the algorithm, see Bjoern Doebel's SWIFI/RATFlip class
// some declarations
GPRegisterId bochs_reg = Udis86::udisGPRToFailBochsGPR(which);
param->msg.set_register_offset(static_cast<L4SysProtoMsg_RegisterType>(bochs_reg + 1));
ConcreteCPU &cpu = simulator.getCPU(0);
Register *bochsRegister = cpu.getRegister(bochs_reg);
Register *exchangeRegister = NULL;
// first, decide if the fault hits a register bound to this thread
// (ten percent chance)
if (rand() % 10 == 0) {
// assure exchange of registers
unsigned int exchg_reg = rand() % 7;
if (exchg_reg == bochs_reg)
exchg_reg++;
exchangeRegister = cpu.getRegister(exchg_reg);
param->msg.set_details(l4sysRegisterConversion.output(exchg_reg + 1));
}
// otherwise, just assume it is stored in an unused register
}
// restore the actual value of the register
// in reality, it would never have been overwritten
cpu.setRegisterContent(bochsRegister, data);
// log the injection
logInjection();
// prepare the fault
regdata_t data = cpu.getRegisterContent(bochsRegister);
if (rnd > 0) {
//input register - do the fault injection here
regdata_t newdata = 0;
if (exchangeRegister != NULL) {
// the data is taken from a process register chosen before
newdata = cpu.getRegisterContent(exchangeRegister);
} else {
// the data comes from an uninitialised register
newdata = rand();
stringstream ss;
ss << "0x" << hex << newdata;
param->msg.set_details(ss.str());
}
cpu.setRegisterContent(bochsRegister, newdata);
}
} else if (exp_type == param->msg.ALUINSTR) {
static BochsALUInstructions aluInstrObject(aluInstructions, aluInstructionsSize);
// find the closest ALU instruction after the current IP
bxInstruction_c *currInstr;
while (!aluInstrObject.isALUInstruction(
currInstr = simulator.getCurrentInstruction()) &&
simulator.getCPU(0).getInstructionPointer() != L4SYS_FUNC_EXIT) {
// execute the instruction
singleStep(true);
// restore the register if we are still in the thread
if (rnd == 0) {
// output register - do the fault injection here
if (exchangeRegister != NULL) {
// write the result into the wrong local register
regdata_t newdata = cpu.getRegisterContent(bochsRegister);
cpu.setRegisterContent(exchangeRegister, newdata);
}
// otherwise, just assume it is stored in an unused register
}
// restore the actual value of the register
// in reality, it would never have been overwritten
cpu.setRegisterContent(bochsRegister, data);
// log the injection
logInjection();
} else if (exp_type == param->msg.ALUINSTR) {
static BochsALUInstructions aluInstrObject(aluInstructions, aluInstructionsSize);
// find the closest ALU instruction after the current IP
bxInstruction_c *currInstr;
while (!aluInstrObject.isALUInstruction(
currInstr = simulator.getCurrentInstruction()) &&
simulator.getCPU(0).getInstructionPointer() != L4SYS_FUNC_EXIT) {
singleStep(true);
}
if (simulator.getCPU(0).getInstructionPointer() == L4SYS_FUNC_EXIT) {
stringstream ss;
ss << "Reached the end of the experiment ";
ss << "without finding an appropriate instruction";
terminateWithError(ss.str(), 34);
}
// store the real injection point
param->msg.set_injection_ip(simulator.getCPU(0).getInstructionPointer());
// now exchange it with a random equivalent
bxInstruction_c newInstr;
string details;
aluInstrObject.randomEquivalent(newInstr, details);
if (memcmp(&newInstr, currInstr, sizeof(bxInstruction_c)) == 0) {
// something went wrong - exit experiment
terminateWithError(
"Did not hit an ALU instruction - correct the source code please!",
40);
}
// record information on the new instruction
param->msg.set_details(details);
// inject it
injectInstruction(currInstr, &newInstr);
// do the logging
logInjection();
}
#endif
if (simulator.getCPU(0).getInstructionPointer() == L4SYS_FUNC_EXIT) {
stringstream ss;
ss << "Reached the end of the experiment ";
ss << "without finding an appropriate instruction";
// aftermath
BPSingleListener ev_done(L4SYS_FUNC_EXIT, L4SYS_ADDRESS_SPACE);
simulator.addListener(&ev_done);
terminateWithError(ss.str(), 34);
}
unsigned instr_left = L4SYS_TOTINSTR - instr_offset; // XXX offset is in NUMINSTR, TOTINSTR is higher
BPSingleListener ev_incomplete(ANY_ADDR, L4SYS_ADDRESS_SPACE);
ev_incomplete.setCounter(static_cast<unsigned>(instr_left * 1.1));
simulator.addListener(&ev_incomplete);
// store the real injection point
param->msg.set_injection_ip(simulator.getCPU(0).getInstructionPointer());
TimerListener ev_timeout(calculateTimeout(instr_left));
simulator.addListener(&ev_timeout);
// now exchange it with a random equivalent
bxInstruction_c newInstr;
string details;
aluInstrObject.randomEquivalent(newInstr, details);
if (memcmp(&newInstr, currInstr, sizeof(bxInstruction_c)) == 0) {
// something went wrong - exit experiment
terminateWithError(
"Did not hit an ALU instruction - correct the source code please!",
40);
}
// record information on the new instruction
param->msg.set_details(details);
//do not discard output recorded so far
BaseListener *ev = waitIOOrOther(false);
// inject it
injectInstruction(currInstr, &newInstr);
// do the logging
logInjection();
}
// aftermath
BPSingleListener ev_done(L4SYS_FUNC_EXIT, L4SYS_ADDRESS_SPACE);
simulator.addListener(&ev_done);
unsigned instr_left = L4SYS_TOTINSTR - instr_offset; // XXX offset is in NUMINSTR, TOTINSTR is higher
BPSingleListener ev_incomplete(ANY_ADDR, L4SYS_ADDRESS_SPACE);
ev_incomplete.setCounter(
static_cast<unsigned>(instr_left * 1.1));
simulator.addListener(&ev_incomplete);
TimerListener ev_timeout(calculateTimeout(instr_left));
simulator.addListener(&ev_timeout);
//do not discard output recorded so far
BaseListener *ev = waitIOOrOther(false);
/* copying a string object that contains control sequences
* unfortunately does not work with the library I am using,
* which is why output is passed on as C string and
* the string compare is done on C strings
*/
if (ev == &ev_done) {
if (strcmp(output.c_str(), golden_run.c_str()) == 0) {
log << "Result DONE" << endl;
param->msg.set_resulttype(param->msg.DONE);
/* copying a string object that contains control sequences
* unfortunately does not work with the library I am using,
* which is why output is passed on as C string and
* the string compare is done on C strings
*/
if (ev == &ev_done) {
if (strcmp(currentOutput.c_str(), golden_run.c_str()) == 0) {
log << "Result DONE" << endl;
result->set_resulttype(param->msg.DONE);
} else {
log << "Result WRONG" << endl;
result->set_resulttype(param->msg.WRONG);
result->set_output(sanitised(currentOutput.c_str()));
}
} else if (ev == &ev_incomplete) {
log << "Result INCOMPLETE" << endl;
result->set_resulttype(param->msg.INCOMPLETE);
result->set_resultdata(simulator.getCPU(0).getInstructionPointer());
result->set_output(sanitised(currentOutput.c_str()));
} else if (ev == &ev_timeout) {
log << "Result TIMEOUT" << endl;
result->set_resulttype(param->msg.TIMEOUT);
result->set_resultdata(simulator.getCPU(0).getInstructionPointer());
result->set_output(sanitised(currentOutput.c_str()));
} else {
log << "Result WRONG" << endl;
param->msg.set_resulttype(param->msg.WRONG);
param->msg.set_output(sanitised(output.c_str()));
log << "Result WTF?" << endl;
stringstream ss;
ss << "eventid " << ev;
terminateWithError(ss.str(), 50);
}
} else if (ev == &ev_incomplete) {
log << "Result INCOMPLETE" << endl;
param->msg.set_resulttype(param->msg.INCOMPLETE);
param->msg.set_resultdata(
simulator.getCPU(0).getInstructionPointer());
param->msg.set_output(sanitised(output.c_str()));
} else if (ev == &ev_timeout) {
log << "Result TIMEOUT" << endl;
param->msg.set_resulttype(param->msg.TIMEOUT);
param->msg.set_resultdata(
simulator.getCPU(0).getInstructionPointer());
param->msg.set_output(sanitised(output.c_str()));
} else {
log << "Result WTF?" << endl;
stringstream ss;
ss << "eventid " << ev;
terminateWithError(ss.str(), 50);
}
m_jc.sendResult(*param);

View File

@ -30,6 +30,7 @@ private:
fail::JobClient m_jc; //!< the job client connecting to the campaign server
fail::Logger log; //<! the logger
L4SysExperimentData *param; //<! the parameter set currently in use by the client
std::string currentOutput; //<! output for the current experiment run
public:
L4SysExperiment();
~L4SysExperiment();

View File

@ -1,4 +1,7 @@
import "DatabaseCampaignMessage.proto";
message L4SysProtoMsg {
// experiment types
enum ExperimentType {
GPRFLIP = 1;
@ -6,10 +9,6 @@ message L4SysProtoMsg {
IDCFLIP = 3;
ALUINSTR = 4;
}
// parameters
required ExperimentType exp_type = 1;
required int32 instr_offset = 2;
required int32 bit_offset = 3;
// registers
enum RegisterType {
@ -22,7 +21,6 @@ message L4SysProtoMsg {
ESI = 7;
EDI = 8;
}
optional RegisterType register_offset = 4;
// results
// make these optional to reduce overhead for server->client communication
@ -33,14 +31,26 @@ message L4SysProtoMsg {
WRONG = 4;
UNKNOWN = 5;
}
// instruction pointer where injection was done
optional uint32 injection_ip = 5;
// result type, see above
optional ResultType resulttype = 6;
// result data, depending on resulttype (see source code)
optional uint32 resultdata = 7;
// generated output
optional string output = 8;
// optional textual description of what happened
optional string details = 9;
required DatabaseCampaignMessage fsppilot = 1;
required ExperimentType exp_type = 2;
repeated group Result = 3 {
// parameters
required int32 instr_offset = 1;
required int32 bit_offset = 2 [(sql_primary_key) = true];
optional RegisterType register_offset = 3;
// instruction pointer where injection was done
optional uint32 injection_ip = 4;
// result type, see above
optional ResultType resulttype = 5;
// result data, depending on resulttype (see source code)
optional uint32 resultdata = 6;
// generated output
optional string output = 7;
// optional textual description of what happened
optional string details = 8;
}
}