diff --git a/src/experiments/l4-sys/CMakeLists.txt b/src/experiments/l4-sys/CMakeLists.txt index e7dba56e..e9041057 100644 --- a/src/experiments/l4-sys/CMakeLists.txt +++ b/src/experiments/l4-sys/CMakeLists.txt @@ -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) diff --git a/src/experiments/l4-sys/campaign.cc b/src/experiments/l4-sys/campaign.cc index ed5626e4..e6a62a1a 100644 --- a/src/experiments/l4-sys/campaign.cc +++ b/src/experiments/l4-sys/campaign.cc @@ -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); +} diff --git a/src/experiments/l4-sys/campaign.hpp b/src/experiments/l4-sys/campaign.hpp index cad4f060..ec68f624 100644 --- a/src/experiments/l4-sys/campaign.hpp +++ b/src/experiments/l4-sys/campaign.hpp @@ -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 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__ diff --git a/src/experiments/l4-sys/experiment.cc b/src/experiments/l4-sys/experiment.cc index 7732c225..07f21128 100644 --- a/src/experiments/l4-sys/experiment.cc +++ b/src/experiments/l4-sys/experiment.cc @@ -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 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(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(&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(&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(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(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(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(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); diff --git a/src/experiments/l4-sys/experiment.hpp b/src/experiments/l4-sys/experiment.hpp index bebcbed2..edc01b2e 100644 --- a/src/experiments/l4-sys/experiment.hpp +++ b/src/experiments/l4-sys/experiment.hpp @@ -30,6 +30,7 @@ private: fail::JobClient m_jc; //!< the job client connecting to the campaign server fail::Logger log; //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; + } }