diff --git a/src/experiments/l4-sys/CMakeLists.txt b/src/experiments/l4-sys/CMakeLists.txt index 1ea51cc9..8bccf74f 100644 --- a/src/experiments/l4-sys/CMakeLists.txt +++ b/src/experiments/l4-sys/CMakeLists.txt @@ -20,8 +20,6 @@ set(MY_CAMPAIGN_SRCS UDIS86.cc InstructionFilter.hpp InstructionFilter.cc - conversion.hpp - conversion.cc ) #### PROTOBUFS #### diff --git a/src/experiments/l4-sys/campaign.cc b/src/experiments/l4-sys/campaign.cc index 5815ec33..bd45cbec 100644 --- a/src/experiments/l4-sys/campaign.cc +++ b/src/experiments/l4-sys/campaign.cc @@ -1,164 +1,12 @@ -#include -#include - #include "campaign.hpp" -#include "experimentInfo.hpp" -#include "conversion.hpp" -#include "comm/DatabaseCampaignMessage.pb.h" +#include "experiment.hpp" #include "cpn/CampaignManager.hpp" -#include "util/Logger.hpp" -#include "sal/SALConfig.hpp" - -using namespace std; -using namespace fail; - -char const * const results_csv = "l4sys.csv"; - -extern L4SysConversion l4sysResultConversion; -extern L4SysConversion l4sysExperimentConversion; -extern L4SysConversion l4sysRegisterConversion; - -#if 0 -bool L4SysCampaign::run() { - Logger log("L4SysCampaign"); - - ifstream test(results_csv); - if (test.is_open()) { - log << results_csv << " already exists" << endl; - return false; - } - - ofstream results(results_csv); - if (!results.is_open()) { - log << "failed to open " << results_csv << endl; - return false; - } - - log << "startup" << endl; - - int count = 0; - srand(time(NULL)); - - for (int i = 0; i < L4SYS_NUMINSTR; ++i) { - for (int r = 1; r < 9; ++r) { - for (int b = 0; b < 32; ++b) { - L4SysExperimentData *d = new L4SysExperimentData; - d->msg.set_exp_type(d->msg.GPRFLIP); - d->msg.set_register_offset(static_cast(r)); - d->msg.set_instr_offset(i); - d->msg.set_bit_offset(b); - campaignmanager.addParam(d); - ++count; - } - } - } - - for (int i = 0; i < 20000; ++i) { - L4SysExperimentData *d = new L4SysExperimentData; - d->msg.set_exp_type(d->msg.GPRFLIP); - // affect a random register - int reg_offset = rand() % 8 + 1; - d->msg.set_register_offset( - static_cast(reg_offset)); - // modify for a random instruction - int instr_offset = rand() % L4SYS_NUMINSTR; - d->msg.set_instr_offset(instr_offset); - // modify a random bit - int bit_offset = rand() % 32; - d->msg.set_bit_offset(bit_offset); - - campaignmanager.addParam(d); - ++count; - } - for (int i = 0; i < 20000; ++i) { - L4SysExperimentData *d = new L4SysExperimentData; - d->msg.set_exp_type(d->msg.ALUINSTR); - // modify for a random instruction - int instr_offset = rand() % L4SYS_NUMINSTR; - d->msg.set_instr_offset(instr_offset); - // this value is not required for this experiment, so set it to an arbitrary value - d->msg.set_bit_offset(0); - - campaignmanager.addParam(d); - ++count; - } - for (int i = 0; i < 20000; ++i) { - L4SysExperimentData *d = new L4SysExperimentData; - d->msg.set_exp_type(d->msg.IDCFLIP); - // modify for a random instruction - int instr_offset = rand() % L4SYS_NUMINSTR; - d->msg.set_instr_offset(instr_offset); - // modify a random bit - Bochs supports at most 15 bytes of instruction - int bit_offset = rand() % 125; - d->msg.set_bit_offset(bit_offset); - - campaignmanager.addParam(d); - ++count; - } - for (int i = 0; i < 20000; ++i) { - L4SysExperimentData *d = new L4SysExperimentData; - d->msg.set_exp_type(d->msg.RATFLIP); - // modify for a random instruction - int instr_offset = rand() % L4SYS_NUMINSTR; - d->msg.set_instr_offset(instr_offset); - // this value is not required for this experiment, so set it to an arbitrary value - d->msg.set_bit_offset(0); - - campaignmanager.addParam(d); - ++count; - } - - campaignmanager.noMoreParameters(); - log << "done enqueueing parameter sets (" << count << ")." << endl; - - // collect results - L4SysExperimentData *res; - int rescount = 0; - results - << "exp_type,injection_ip,register,instr_offset,injection_bit,resulttype,resultdata,output,details" - << endl; - while ((res = static_cast(campaignmanager.getDone()))) { - rescount++; - - results << l4sysExperimentConversion.output(res->msg.exp_type()) - << "," << hex << res->msg.injection_ip() << dec << ","; - if (res->msg.has_register_offset()) - results << l4sysRegisterConversion.output(res->msg.register_offset()); - else - results << "None"; - results << "," << res->msg.instr_offset() << "," << res->msg.bit_offset() - << "," - << l4sysResultConversion.output(res->msg.resulttype()) << "," - << res->msg.resultdata(); - if (res->msg.has_output()) - results << "," << res->msg.output(); - if (res->msg.has_details()) - results << "," << res->msg.details(); - results << endl; - delete res; - } - - log << "done. sent " << count << " received " << rescount << endl; - results.close(); - - 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); - //d->msg.set_exp_type(d->msg.MEM); - campaignmanager.addParam(d); + //d->msg.set_exp_type(d->msg.GPRFLIP); + d->msg.set_exp_type(d->msg.MEM); + fail::campaignmanager.addParam(d); } diff --git a/src/experiments/l4-sys/campaign.hpp b/src/experiments/l4-sys/campaign.hpp index ec68f624..ab883d30 100644 --- a/src/experiments/l4-sys/campaign.hpp +++ b/src/experiments/l4-sys/campaign.hpp @@ -13,15 +13,10 @@ public: }; 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/conversion.cc b/src/experiments/l4-sys/conversion.cc deleted file mode 100644 index 7fc44c76..00000000 --- a/src/experiments/l4-sys/conversion.cc +++ /dev/null @@ -1,16 +0,0 @@ -#include "conversion.hpp" - -char const *l4sys_output_result_strings[] = { "Unknown", "No effect", "Incomplete execution", "Crash", "Silent data corruption", "Error" }; -char const *l4sys_output_experiment_strings[] = { "Unknown", "GPR Flip", "RAT Flip", "IDC Flip", "ALU Instr Flip" }; -char const *l4sys_output_register_strings[] = { "Unknown", "EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI" }; - -L4SysConversion l4sysResultConversion( - l4sys_output_result_strings, - sizeof(l4sys_output_result_strings)); -L4SysConversion l4sysExperimentConversion( - l4sys_output_experiment_strings, - sizeof(l4sys_output_experiment_strings)); -L4SysConversion l4sysRegisterConversion( - l4sys_output_register_strings, - sizeof(l4sys_output_register_strings)); - diff --git a/src/experiments/l4-sys/conversion.hpp b/src/experiments/l4-sys/conversion.hpp deleted file mode 100644 index 515640de..00000000 --- a/src/experiments/l4-sys/conversion.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef __L4SYS_CONVERSION_HPP__ - #define __L4SYS_CONVERSION_HPP__ - -#include "l4sys.pb.h" - -class L4SysConversion { -public: - L4SysConversion(char const **strings, size_t array_size) - : m_Strings(strings) - { - m_ElementCount = array_size / sizeof(char*); - } - char const * output(unsigned int res) { - if (res == 0 || res >= m_ElementCount) { - return m_Strings[0]; - } else { - return m_Strings[res]; - } - } -private: - char const **m_Strings; - size_t m_ElementCount; -}; - -#endif // __L4SYS_CONVERSION_HPP__ diff --git a/src/experiments/l4-sys/experiment.cc b/src/experiments/l4-sys/experiment.cc index 4c8f3cd6..843b9fb2 100644 --- a/src/experiments/l4-sys/experiment.cc +++ b/src/experiments/l4-sys/experiment.cc @@ -36,9 +36,6 @@ using namespace fail; save, and restore. Enable these in the configuration. #endif -//string golden_run; -extern L4SysConversion l4sysRegisterConversion; - string L4SysExperiment::sanitised(const string &in_str) { string result; int in_str_size = in_str.size(); @@ -474,8 +471,7 @@ void L4SysExperiment::collectInstructionTrace(fail::BPSingleListener* bp) #if 0 if (curr_addr < 0xC0000000) // XXX filter for kernel-only experiment continue; -#endif - +#endif currtime = simulator.getTimerTicks(); deltatime = currtime - prevtime; @@ -816,7 +812,7 @@ bool L4SysExperiment::run() BPSingleListener ev_longjmp(L4SYS_BREAK_LONGJMP); simulator.addListener(&ev_longjmp); - //If we come to our own exit function, we can stop + //If we come to our own exit function, we can stop BPSingleListener ev_exit(L4SYS_BREAK_EXIT); simulator.addListener(&ev_exit); @@ -844,10 +840,6 @@ bool L4SysExperiment::run() << (void*)&ev_incomplete << endl; BaseListener *ev = afterInjection(result); log << "afterInj: res.devstep = " << result->deviate_steps() << endl; -#if 0 - //do not discard output recorded so far - BaseListener *ev = waitIOOrOther(false); -#endif /* copying a string object that contains control sequences * unfortunately does not work with the library I am using, @@ -875,11 +867,11 @@ bool L4SysExperiment::run() result->set_resulttype(param->msg.TIMEOUT); result->set_resultdata(simulator.getCPU(0).getInstructionPointer()); result->set_output(sanitised(currentOutput.c_str())); - } else if (ev == &ev_exit) { - log << "Result FAILSTOP" << endl; - result->set_resulttype(param->msg.FAILSTOP); - result->set_resultdata(simulator.getCPU(0).getInstructionPointer()); - result->set_output(sanitised(currentOutput.c_str())); + } else if (ev == &ev_exit) { + log << "Result FAILSTOP" << endl; + result->set_resulttype(param->msg.FAILSTOP); + result->set_resultdata(simulator.getCPU(0).getInstructionPointer()); + result->set_output(sanitised(currentOutput.c_str())); } else { log << "Result WTF?" << endl; stringstream ss; @@ -890,220 +882,6 @@ bool L4SysExperiment::run() m_jc.sendResult(*param); -// 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 { - 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 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) { - /* - * 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; - } else { - which = _ud.operand[operands[rnd]].base; - } - } - /* ============================================ */ - /* end Bjoern Doebel's code (slightly modified) */ - - } 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(); - stringstream ss; - ss << "0x" << hex << newdata; - param->msg.set_details(ss.str()); - } - cpu.setRegisterContent(bochsRegister, newdata); - } - - // 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 - #endif terminate(0); diff --git a/src/experiments/l4-sys/experimentInfo.hpp b/src/experiments/l4-sys/experimentInfo.hpp index 3901beb0..40d684e2 100644 --- a/src/experiments/l4-sys/experimentInfo.hpp +++ b/src/experiments/l4-sys/experimentInfo.hpp @@ -6,23 +6,29 @@ // the bounds of the program (space, instructions and time) // client -#define L4SYS_ADDRESS_SPACE 0x1fd4c000 +#define L4SYS_ADDRESS_SPACE 0x1fd77000 // server #define L4SYS_ADDRESS_SPACE_TRACE L4SYS_ADDRESS_SPACE //#define L4SYS_ADDRESS_SPACE_TRACE 0x1fd4c000 +#define L4SYS_exp_start 0x20000216 +#define L4SYS_exp_end 0x2000029c +#define L4SYS_inj_start 0x2000022f +#define L4SYS_inj_end 0x20000252 + // FUNC_{ENTRY,EXIT} specifies the range that needs to // be captured to log program output properly -#define L4SYS_FUNC_ENTRY 0x20000220 -#define L4SYS_FUNC_EXIT 0x20000216 +#define L4SYS_FUNC_ENTRY L4SYS_exp_start +#define L4SYS_FUNC_EXIT L4SYS_exp_end // FILTER_{ENTRY,EXIT} specifies the range that injections // should be carried out on (should be a subset of the above) // and only works with FILTER_INSTRUCTIONS turned on -#define L4SYS_FILTER_ENTRY 0x200002ba -#define L4SYS_FILTER_EXIT 0x20000444 +#define L4SYS_FILTER_ENTRY L4SYS_inj_start +#define L4SYS_FILTER_EXIT L4SYS_inj_end -#define L4SYS_BREAK_BLINK 0xf004b800 -#define L4SYS_BREAK_LONGJMP 0xf004c88e +#define L4SYS_BREAK_BLINK 0x0 +#define L4SYS_BREAK_LONGJMP 0x0 +#define L4SYS_BREAK_EXIT 0x0 // select instruction filtering // XXX: this should be always on and the code should be @@ -31,12 +37,12 @@ #define L4SYS_FILTER_INSTRUCTIONS 1 // kernel: 2377547, userland: 79405472 -#define L4SYS_NUMINSTR 27025 -#define L4SYS_TOTINSTR 189122 +#define L4SYS_NUMINSTR 16 +#define L4SYS_TOTINSTR 58401 #define L4SYS_BOCHS_IPS 5000000 // several file names used -#define L4SYS_STATE_FOLDER "l4sys.state" +#define L4SYS_STATE_FOLDER "l4sys.state" #define L4SYS_INSTRUCTION_LIST "ip.list" #define L4SYS_ALU_INSTRUCTIONS "alu.list" #define L4SYS_CORRECT_OUTPUT "golden.out"