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) find_package(LibUdis86 REQUIRED)
include_directories(${LIBUDIS86_INCLUDE_DIRS}) include_directories(${LIBUDIS86_INCLUDE_DIRS})
link_directories(${LIBUDIS86_LINK_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}) target_link_libraries(fail-${EXPERIMENT_NAME} ${LIBUDIS86_LIBRARIES} ${PROTOBUF_LIBRARY})
## This is the example's campaign server distributing experiment parameters ## This is the example's campaign server distributing experiment parameters
add_executable(${EXPERIMENT_NAME}-server main.cc) 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) install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin)

View File

@ -4,6 +4,7 @@
#include "campaign.hpp" #include "campaign.hpp"
#include "experimentInfo.hpp" #include "experimentInfo.hpp"
#include "conversion.hpp" #include "conversion.hpp"
#include "comm/DatabaseCampaignMessage.pb.h"
#include "cpn/CampaignManager.hpp" #include "cpn/CampaignManager.hpp"
#include "util/Logger.hpp" #include "util/Logger.hpp"
#include "sal/SALConfig.hpp" #include "sal/SALConfig.hpp"
@ -17,6 +18,7 @@ extern L4SysConversion l4sysResultConversion;
extern L4SysConversion l4sysExperimentConversion; extern L4SysConversion l4sysExperimentConversion;
extern L4SysConversion l4sysRegisterConversion; extern L4SysConversion l4sysRegisterConversion;
#if 0
bool L4SysCampaign::run() { bool L4SysCampaign::run() {
Logger log("L4SysCampaign"); Logger log("L4SysCampaign");
@ -51,7 +53,6 @@ bool L4SysCampaign::run() {
} }
} }
#if 0
for (int i = 0; i < 20000; ++i) { for (int i = 0; i < 20000; ++i) {
L4SysExperimentData *d = new L4SysExperimentData; L4SysExperimentData *d = new L4SysExperimentData;
d->msg.set_exp_type(d->msg.GPRFLIP); d->msg.set_exp_type(d->msg.GPRFLIP);
@ -106,7 +107,6 @@ bool L4SysCampaign::run() {
campaignmanager.addParam(d); campaignmanager.addParam(d);
++count; ++count;
} }
#endif
campaignmanager.noMoreParameters(); campaignmanager.noMoreParameters();
log << "done enqueueing parameter sets (" << count << ")." << endl; log << "done enqueueing parameter sets (" << count << ")." << endl;
@ -143,3 +143,21 @@ bool L4SysCampaign::run() {
return true; 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__ #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 "comm/ExperimentData.hpp"
#include "l4sys.pb.h" #include "l4sys.pb.h"
#include <google/protobuf/descriptor.h>
class L4SysExperimentData : public fail::ExperimentData { class L4SysExperimentData : public fail::ExperimentData {
public: public:
@ -11,9 +12,16 @@ public:
L4SysExperimentData() : fail::ExperimentData(&msg) {} L4SysExperimentData() : fail::ExperimentData(&msg) {}
}; };
class L4SysCampaign : public fail::Campaign { class L4SysCampaign : public fail::DatabaseCampaign {
#if 0
public: public:
virtual bool run(); 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__ #endif // __L4SYS_CAMPAIGN_HPP__

View File

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

View File

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

View File

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