diff --git a/src/experiments/l4-sys/CMakeLists.txt b/src/experiments/l4-sys/CMakeLists.txt index 0f1ba777..94136e23 100644 --- a/src/experiments/l4-sys/CMakeLists.txt +++ b/src/experiments/l4-sys/CMakeLists.txt @@ -20,6 +20,8 @@ set(MY_CAMPAIGN_SRCS UDIS86.cc InstructionFilter.hpp InstructionFilter.cc + conversion.hpp + conversion.cc ) #### PROTOBUFS #### diff --git a/src/experiments/l4-sys/Listener.cc.patch b/src/experiments/l4-sys/Listener.cc.patch deleted file mode 100644 index 5b34687b..00000000 --- a/src/experiments/l4-sys/Listener.cc.patch +++ /dev/null @@ -1,16 +0,0 @@ -62c62 -< if (m_Data.getAddressSpace() == ANY_ADDR || m_Data.getAddressSpace() == address_space) ---- -> if (m_Data.getAddressSpace() == ANY_ADDR || m_Data.getAddressSpace() == address_space) { -63a64 -> } -86c87,91 -< if (m_WatchInstrPtr == ANY_ADDR || m_WatchInstrPtr == pEv->getTriggerInstructionPointer()) ---- -> if (m_WatchInstrPtr == ANY_ADDR || m_WatchInstrPtr == pEv->getTriggerInstructionPointer()) { -> address_t address_space = pEv->getAddressSpace(); -> if (address_space) { -> fprintf(stderr, "Got a match; address space: 0x%x\n", address_space); -> } -87a93 -> } diff --git a/src/experiments/l4-sys/campaign.cc b/src/experiments/l4-sys/campaign.cc index d03790c8..6a9300d4 100644 --- a/src/experiments/l4-sys/campaign.cc +++ b/src/experiments/l4-sys/campaign.cc @@ -3,6 +3,7 @@ #include "campaign.hpp" #include "experimentInfo.hpp" +#include "conversion.hpp" #include "cpn/CampaignManager.hpp" #include "util/Logger.hpp" #include "sal/SALConfig.hpp" @@ -11,10 +12,8 @@ using namespace std; using namespace fail; char const * const results_csv = "l4sys.csv"; -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" }; +#if 0 #define OUTPUT_CASE(OUTPUT) case L4SysProtoMsg::OUTPUT: return l4sys_output_result_strings[L4SysProtoMsg::OUTPUT]; std::string L4SysCampaign::output_result(L4SysProtoMsg_ResultType res) { switch (res) { @@ -56,6 +55,11 @@ std::string L4SysCampaign::output_register(L4SysProtoMsg_RegisterType res) { } } #undef OUTPUT_CASE +#endif + +extern L4SysConversion l4sysResultConversion; +extern L4SysConversion l4sysExperimentConversion; +extern L4SysConversion l4sysRegisterConversion; bool L4SysCampaign::run() { Logger log("L4SysCampaign"); @@ -77,6 +81,7 @@ bool L4SysCampaign::run() { int count = 0; srand(time(NULL)); +#if 0 for (int i = 0; i < 20000; ++i) { L4SysExperimentData *d = new L4SysExperimentData; d->msg.set_exp_type(d->msg.GPRFLIP); @@ -119,7 +124,8 @@ bool L4SysCampaign::run() { campaignmanager.addParam(d); ++count; } - for (int i = 0; i < 20000; ++i) { + #endif + for (int i = 0; i < 5000; ++i) { L4SysExperimentData *d = new L4SysExperimentData; d->msg.set_exp_type(d->msg.RATFLIP); // modify for a random instruction @@ -144,13 +150,15 @@ bool L4SysCampaign::run() { while ((res = static_cast(campaignmanager.getDone()))) { rescount++; - results << output_experiment(res->msg.exp_type()) << "," << hex << res->msg.injection_ip() << dec << ","; + results << l4sysExperimentConversion.output(res->msg.exp_type()) + << "," << hex << res->msg.injection_ip() << dec << ","; if (res->msg.has_register_offset()) - results << output_register(res->msg.register_offset()); + results << l4sysRegisterConversion.output(res->msg.register_offset()); else results << "None"; results << "," << res->msg.instr_offset() << "," << res->msg.bit_offset() - << "," << output_result(res->msg.resulttype()) << "," + << "," + << l4sysResultConversion.output(res->msg.resulttype()) << "," << res->msg.resultdata(); if (res->msg.has_output()) results << "," << res->msg.output(); diff --git a/src/experiments/l4-sys/campaign.hpp b/src/experiments/l4-sys/campaign.hpp index 8258751d..cad4f060 100644 --- a/src/experiments/l4-sys/campaign.hpp +++ b/src/experiments/l4-sys/campaign.hpp @@ -14,10 +14,6 @@ public: class L4SysCampaign : public fail::Campaign { public: virtual bool run(); -private: - std::string output_result(L4SysProtoMsg_ResultType res); - std::string output_experiment(L4SysProtoMsg_ExperimentType res); - std::string output_register(L4SysProtoMsg_RegisterType res); }; #endif // __L4SYS_CAMPAIGN_HPP__ diff --git a/src/experiments/l4-sys/conversion.cc b/src/experiments/l4-sys/conversion.cc new file mode 100644 index 00000000..7fc44c76 --- /dev/null +++ b/src/experiments/l4-sys/conversion.cc @@ -0,0 +1,16 @@ +#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 new file mode 100644 index 00000000..515640de --- /dev/null +++ b/src/experiments/l4-sys/conversion.hpp @@ -0,0 +1,25 @@ +#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 857955bf..9b67134b 100644 --- a/src/experiments/l4-sys/experiment.cc +++ b/src/experiments/l4-sys/experiment.cc @@ -12,6 +12,7 @@ #include "InstructionFilter.hpp" #include "aluinstr.hpp" #include "campaign.hpp" +#include "conversion.hpp" #include "sal/SALConfig.hpp" #include "sal/SALInst.hpp" @@ -35,6 +36,7 @@ using namespace fail; string output; string golden_run; +extern L4SysConversion l4sysRegisterConversion; string L4SysExperiment::sanitised(const string &in_str) { string result; @@ -191,6 +193,17 @@ void L4SysExperiment::terminate(int reason) { simulator.terminate(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); + + m_jc.sendResult(*param); + terminate(reason); +} + bool L4SysExperiment::run() { BPSingleListener bp(0, L4SYS_ADDRESS_SPACE); srand(time(NULL)); @@ -203,9 +216,11 @@ bool L4SysExperiment::run() { simulator.addListenerAndResume(&bp); log << "test function entry reached, saving state" << endl; - log << "EIP = " << hex << bp.getTriggerInstructionPointer() << " or " + log << "EIP: expected " << hex << bp.getTriggerInstructionPointer() + << " and actually got " << simulator.getCPU(0).getInstructionPointer() << endl; + log << "check the source code if the two instruction pointers are not equal" << endl; simulator.save(L4SYS_STATE_FOLDER); #elif PREPARATION_STEP == 2 // STEP 2: determine instructions executed @@ -375,28 +390,16 @@ bool L4SysExperiment::run() { ss << "SANITY CHECK FAILED: " << injection_ip << " != " << curr_instr.trigger_addr; log << ss.str() << endl; - param->msg.set_resulttype(param->msg.UNKNOWN); - param->msg.set_resultdata(injection_ip); - param->msg.set_details(ss.str()); - - m_jc.sendResult(*param); - terminate(20); + terminateWithError(ss.str(), 20); } #endif // inject if (exp_type == param->msg.GPRFLIP) { if (!param->msg.has_register_offset()) { - param->msg.set_resulttype(param->msg.UNKNOWN); - param->msg.set_resultdata( - simulator.getCPU(0).getInstructionPointer()); - param->msg.set_output(sanitised(output.c_str())); - - stringstream ss; - ss << "Sent package did not contain the injection location (register offset)"; - param->msg.set_details(ss.str()); - m_jc.sendResult(*param); - terminate(30); + terminateWithError( + "Sent package did not contain the injection location (register offset)", + 30); } int reg_offset = param->msg.register_offset(); ConcreteCPU& cpu = simulator.getCPU(0); @@ -448,11 +451,6 @@ bool L4SysExperiment::run() { // do the logging logInjection(); } else if (exp_type == param->msg.RATFLIP) { - /* - TODO: provide information on the affected register - in param->msg.register and on its destination in - param->msg.details - */ ud_type_t which = UD_NONE; unsigned rnd = 0; Udis86 udis(injection_ip); @@ -460,16 +458,8 @@ bool L4SysExperiment::run() { bxInstruction_c *currInstr = simulator.getCurrentInstruction(); udis.setInputBuffer(calculateInstructionAddress(), currInstr->ilen()); if (!udis.fetchNextInstruction()) { - param->msg.set_resulttype(param->msg.UNKNOWN); - param->msg.set_resultdata( - simulator.getCPU(0).getInstructionPointer()); - param->msg.set_output(sanitised(output.c_str())); - - stringstream ss; - ss << "Could not decode instruction using UDIS86"; - param->msg.set_details(ss.str()); - m_jc.sendResult(*param); - terminate(32); + terminateWithError( + "Could not decode instruction using UDIS86", 32); } ud_t _ud = udis.getCurrentState(); @@ -522,16 +512,11 @@ bool L4SysExperiment::run() { simulator.getCPU(0).getInstructionPointer() != L4SYS_FUNC_EXIT); if (simulator.getCPU(0).getInstructionPointer() == L4SYS_FUNC_EXIT) { - param->msg.set_resulttype(param->msg.UNKNOWN); - param->msg.set_resultdata( - simulator.getCPU(0).getInstructionPointer()); - param->msg.set_output(sanitised(output.c_str())); - stringstream ss; - ss << "Reached the end of the experiment without finding an appropriate instruction"; - param->msg.set_details(ss.str()); - m_jc.sendResult(*param); - terminate(33); + ss << "Reached the end of the experiment "; + ss << "without finding an appropriate instruction"; + + terminateWithError(ss.str(), 33); } // store the real injection point @@ -542,7 +527,8 @@ bool L4SysExperiment::run() { // some declarations GPRegisterId bochs_reg = Udis86::udisGPRToFailBochsGPR(which); - int exchg_reg = -1; + param->msg.set_register_offset( + static_cast(bochs_reg + 1)); ConcreteCPU &cpu = simulator.getCPU(0); Register *bochsRegister = cpu.getRegister(bochs_reg); Register *exchangeRegister = NULL; @@ -551,10 +537,11 @@ bool L4SysExperiment::run() { // (ten percent chance) if (rand() % 10 == 0) { // assure exchange of registers - exchg_reg = rand() % 7; + 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 @@ -562,7 +549,7 @@ bool L4SysExperiment::run() { if (rnd > 0) { //input register - do the fault injection here regdata_t newdata = 0; - if (exchangeRegister >= 0) { + if (exchangeRegister != NULL) { // the data is taken from a process register chosen before newdata = cpu.getRegisterContent(exchangeRegister); } else { @@ -578,7 +565,7 @@ bool L4SysExperiment::run() { // restore the register if we are still in the thread if (rnd == 0) { // output register - do the fault injection here - if (exchangeRegister >= 0) { + if (exchangeRegister != NULL) { // write the result into the wrong local register regdata_t newdata = cpu.getRegisterContent(bochsRegister); cpu.setRegisterContent(exchangeRegister, newdata); @@ -604,16 +591,11 @@ bool L4SysExperiment::run() { } if (simulator.getCPU(0).getInstructionPointer() == L4SYS_FUNC_EXIT) { - param->msg.set_resulttype(param->msg.UNKNOWN); - param->msg.set_resultdata( - simulator.getCPU(0).getInstructionPointer()); - param->msg.set_output(sanitised(output.c_str())); - stringstream ss; - ss << "Reached the end of the experiment without finding an appropriate instruction"; - param->msg.set_details(ss.str()); - m_jc.sendResult(*param); - terminate(33); + ss << "Reached the end of the experiment "; + ss << "without finding an appropriate instruction"; + + terminateWithError(ss.str(), 34); } // store the real injection point @@ -625,16 +607,9 @@ bool L4SysExperiment::run() { aluInstrObject.randomEquivalent(newInstr, details); if (memcmp(&newInstr, currInstr, sizeof(bxInstruction_c)) == 0) { // something went wrong - exit experiment - param->msg.set_resulttype(param->msg.UNKNOWN); - param->msg.set_resultdata( - simulator.getCPU(0).getInstructionPointer()); - param->msg.set_output(sanitised(output.c_str())); - - ostringstream oss; - oss << "Did not hit an ALU instruction - correct the source code please!"; - param->msg.set_details(oss.str()); - m_jc.sendResult(*param); - terminate(40); + terminateWithError( + "Did not hit an ALU instruction - correct the source code please!", + 40); } // record information on the new instruction param->msg.set_details(details); @@ -688,15 +663,9 @@ bool L4SysExperiment::run() { param->msg.set_output(sanitised(output.c_str())); } else { log << "Result WTF?" << endl; - param->msg.set_resulttype(param->msg.UNKNOWN); - param->msg.set_resultdata( - simulator.getCPU(0).getInstructionPointer()); - param->msg.set_output(sanitised(output.c_str())); - stringstream ss; - ss << "eventid " << ev << " EIP " - << simulator.getCPU(0).getInstructionPointer(); - param->msg.set_details(ss.str()); + ss << "eventid " << ev; + terminateWithError(ss.str(), 50); } m_jc.sendResult(*param); diff --git a/src/experiments/l4-sys/experiment.cc.patch b/src/experiments/l4-sys/experiment.cc.patch deleted file mode 100644 index cc61f7ed..00000000 --- a/src/experiments/l4-sys/experiment.cc.patch +++ /dev/null @@ -1,23 +0,0 @@ -195c195 -< BPSingleListener bp(0, L4SYS_ADDRESS_SPACE); ---- -> BPSingleListener bp(0, ANY_ADDR); -202,209c202,210 -< bp.setWatchInstructionPointer(L4SYS_FUNC_ENTRY); -< simulator.addListenerAndResume(&bp); -< -< log << "test function entry reached, saving state" << endl; -< log << "EIP = " << hex << bp.getTriggerInstructionPointer() << " or " -< << simulator.getRegisterManager().getInstructionPointer() -< << endl; -< simulator.save(L4SYS_STATE_FOLDER); ---- -> for (int i = 0; i < 500; i++) { -> bp.setWatchInstructionPointer(L4SYS_FUNC_ENTRY); -> simulator.addListenerAndResume(&bp); -> log << "test function entry reached" << endl; -> log << "EIP = " << hex << bp.getTriggerInstructionPointer() << " or " -> << simulator.getRegisterManager().getInstructionPointer() -> << endl; -> simulator.removeListener(&bp); -> } diff --git a/src/experiments/l4-sys/experiment.hpp b/src/experiments/l4-sys/experiment.hpp index 44219d9a..0ff9be27 100644 --- a/src/experiments/l4-sys/experiment.hpp +++ b/src/experiments/l4-sys/experiment.hpp @@ -102,6 +102,10 @@ private: * Calculate the timeout of the current workload in milliseconds. */ unsigned calculateTimeout(unsigned instr_left); + /** + * Send back the experiment parameter set with a description of the error. + */ + void terminateWithError(std::string details, int reason); }; #endif // __L4SYS_EXPERIMENT_HPP__ diff --git a/src/experiments/l4-sys/experimentInfo.hpp b/src/experiments/l4-sys/experimentInfo.hpp index 94dfc7fe..83849aaf 100644 --- a/src/experiments/l4-sys/experimentInfo.hpp +++ b/src/experiments/l4-sys/experimentInfo.hpp @@ -5,11 +5,11 @@ #define MAX_INSTR_BYTES 15 // the bounds of the program (space, instructions and time) -#define L4SYS_ADDRESS_SPACE 0x203d000 +#define L4SYS_ADDRESS_SPACE 0x1fe0000 #define L4SYS_FUNC_ENTRY 0x10025ca #define L4SYS_FUNC_EXIT 0x1002810 -// kernel: 3597806, userland: 79484908 -#define L4SYS_NUMINSTR 83082714 +// kernel: 2377547, userland: 79405472 +#define L4SYS_NUMINSTR 81783019 #define L4SYS_BOCHS_IPS 5000000 // several file names used diff --git a/src/experiments/l4-sys/l4sys.proto b/src/experiments/l4-sys/l4sys.proto index c99f9215..b2d0e093 100644 --- a/src/experiments/l4-sys/l4sys.proto +++ b/src/experiments/l4-sys/l4sys.proto @@ -12,17 +12,17 @@ message L4SysProtoMsg { required int32 bit_offset = 3; // registers - enum RegisterType { - EAX = 1; - ECX = 2; - EDX = 3; - EBX = 4; - ESP = 5; - EBP = 6; - ESI = 7; - EDI = 8; - } - optional RegisterType register_offset = 4; + enum RegisterType { + EAX = 1; + ECX = 2; + EDX = 3; + EBX = 4; + ESP = 5; + EBP = 6; + ESI = 7; + EDI = 8; + } + optional RegisterType register_offset = 4; // results // make these optional to reduce overhead for server->client communication diff --git a/src/experiments/l4-sys/manual.pdf b/src/experiments/l4-sys/manual.pdf index 919971b1..9b8a0bf9 100644 Binary files a/src/experiments/l4-sys/manual.pdf and b/src/experiments/l4-sys/manual.pdf differ diff --git a/src/experiments/l4-sys/manual.tex b/src/experiments/l4-sys/manual.tex index 8507dd17..a2ebbf20 100644 --- a/src/experiments/l4-sys/manual.tex +++ b/src/experiments/l4-sys/manual.tex @@ -81,8 +81,8 @@ you may set \verb+L4SYS_ADDRESS_SPACE+ to \verb+ANY_ADDR+. Keep in mind that in that case, your instruction addresses must be unique among all those executed in the system, which in general is not the case. -Basically, there are two ways to find out the identifier of a certain -address space in Fail*: You can look up the value in +To find out the value of the address space identifier, you will have to +look up the value in the emulator using a debugger. In the case of Bochs, you may want to study \href{http://bochs.sourceforge.net/doc/docbook/user/internal-debugger.html}{this page}, @@ -90,38 +90,8 @@ and, according to its instructions, dump the content of the CR3 control register at the beginning of your program. -You can also utilise the Fail* framework, which is easier and more reliable, -but as there is no real reason to include this ``feature'' in the framework, -in order to do so, you need to patch it. Namely, -\texttt{src/core/sal/Listener.cc} and -\texttt{src/experiments/l4-sys/experiment.cc} -need to be modified using the two patch files supplied alongside with this -manual in the current directory. -You should check the patch files for their release date and content: -In case the framework's -event handling structure has changed, the line numbers in -\texttt{Listener.cc} are incorrect, -and you need to apply the patch manually. - -As soon as you have applied the patch, set \verb+PREPARATION_STEP+ -to \texttt{1} in \texttt{experimentInfo.hpp} and recompile the framework. -Now start the experiment client (\texttt{fail-client}) in your -emulator directory, and -it will show you which address space is active whenever a -breakpoint triggers. -Ideally, you still have a graphical interface enabled to -monitor your system's progress and check if the breakpoints -are triggered at the right points in time. - -When your program has reached the function entry point, -note the address space and exit the program simply by pressing Ctrl+C. - \subsection{Step 1: Save the initial state of the machine} -If you have modified the Fail* framework in Step 0, -you should now restore the original framework -data using \texttt{svn revert}. - Make sure \verb+PREPARATION_STEP+ is still set to \texttt{1}, and you have set \verb+L4SYS_ADDRESS_SPACE+ accordingly. Now recompile and execute the framework code again, this time with the graphical @@ -297,10 +267,7 @@ the campaign server, from left to right. \section{Known bugs} -At the moment, RATFlip does not provide enough information -to reconstruct the injected fault -(see also the \texttt{TODO} in \texttt{experiment.cc}). -Also, if you need support for more than one processor, +If you need support for more than one processor, you will have to extend the code accordingly: at the moment, when in doubt, it uses the first CPU.