diff --git a/libs2e/configure b/libs2e/configure old mode 100644 new mode 100755 diff --git a/libs2ecore/include/s2e/CorePlugin.h b/libs2ecore/include/s2e/CorePlugin.h index 1082f52f..e4856d19 100644 --- a/libs2ecore/include/s2e/CorePlugin.h +++ b/libs2ecore/include/s2e/CorePlugin.h @@ -508,6 +508,16 @@ class CorePlugin : public Plugin { uint64_t /* address */> onInvalidPCAccess; + /// + /// Signal that is emitted before accessing memory at symbolic address. + /// + sigc::signal /* symbolic Data */, + bool /* is write */> + onSymbolicDataAccessConcreteMemory; + // clang-format on }; diff --git a/libs2ecore/include/s2e/S2EExecutor.h b/libs2ecore/include/s2e/S2EExecutor.h index b386cd9d..a522db67 100644 --- a/libs2ecore/include/s2e/S2EExecutor.h +++ b/libs2ecore/include/s2e/S2EExecutor.h @@ -209,6 +209,8 @@ class S2EExecutor : public klee::Executor { void doDeviceStateRestore(S2EExecutionState *newState); + static void validPathSearcherStateSwitchCallback(void *opaque); + protected: void updateClockScaling(); diff --git a/libs2ecore/src/FunctionHandlers.cpp b/libs2ecore/src/FunctionHandlers.cpp index 8cd50801..2d2d7cdf 100644 --- a/libs2ecore/src/FunctionHandlers.cpp +++ b/libs2ecore/src/FunctionHandlers.cpp @@ -164,9 +164,6 @@ static void handlerBeforeMemoryAccess(klee::Executor *executor, klee::ExecutionS // 1st arg: virtual address klee::ref vaddr = args[0]; - if (isa(vaddr)) { - return; - } // 3rd arg: width Expr::Width width = cast(args[2])->getZExtValue() * 8; @@ -187,6 +184,11 @@ static void handlerBeforeMemoryAccess(klee::Executor *executor, klee::ExecutionS S2EExecutionState *s2eState = static_cast(state); g_s2e->getCorePlugin()->onBeforeSymbolicDataMemoryAccess.emit(s2eState, vaddr, value, flags); + + if (isa(vaddr) && isa(value) && !value->isZero()) { + g_s2e->getCorePlugin()->onSymbolicDataAccessConcreteMemory.emit( + s2eState, cast(vaddr)->getZExtValue(), value, flags); + } } void handlerAfterMemoryAccess(Executor *executor, ExecutionState *state, klee::KInstruction *target, diff --git a/libs2ecore/src/S2EExecutor.cpp b/libs2ecore/src/S2EExecutor.cpp index 7be40c44..f9e78c7a 100644 --- a/libs2ecore/src/S2EExecutor.cpp +++ b/libs2ecore/src/S2EExecutor.cpp @@ -815,6 +815,24 @@ void S2EExecutor::stateSwitchTimerCallback(void *opaque) { libcpu_mod_timer(c->m_stateSwitchTimer, libcpu_get_clock_ms(host_clock) + 100); } +void S2EExecutor::validPathSearcherStateSwitchCallback(void *opaque) { + S2EExecutor *c = (S2EExecutor *) opaque; + + assert(env->current_tb == nullptr); + + if (g_s2e_state) { + c->doLoadBalancing(); + S2EExecutionState *nextState = c->selectNextState(g_s2e_state); + if (nextState) { + g_s2e_state = nextState; + } else { + // Do not reschedule the timer anymore + return; + } + } + libcpu_mod_timer(c->m_stateSwitchTimer, libcpu_get_clock_ms(host_clock) + 100); +} + void S2EExecutor::initializeStateSwitchTimer() { m_stateSwitchTimer = libcpu_new_timer_ms(host_clock, &stateSwitchTimerCallback, this); libcpu_mod_timer(m_stateSwitchTimer, libcpu_get_clock_ms(host_clock) + 100); @@ -1910,7 +1928,11 @@ void S2EExecutor::setupTimersHandler() { bool S2EExecutor::suspendState(S2EExecutionState *state) { if (searcher) { searcher->removeState(state, nullptr); + g_s2e->getDebugStream() << "[states' size " << getStatesCount() << "] " + << "\n"; size_t r = states.erase(state); + g_s2e->getDebugStream() << "[states' size " << getStatesCount() << "] " + << "\n"; assert(r == 1); return true; } diff --git a/libs2eplugins/src/CMakeLists.txt b/libs2eplugins/src/CMakeLists.txt index 32eaeb9c..19aecefd 100644 --- a/libs2eplugins/src/CMakeLists.txt +++ b/libs2eplugins/src/CMakeLists.txt @@ -172,6 +172,8 @@ add_library( s2e/Plugins/uEmu/uEmuExternalInterrupt.cpp s2e/Plugins/uEmu/ARMFunctionMonitor.cpp s2e/Plugins/uEmu/InvalidStatesDetection.cpp + s2e/Plugins/uEmu/DataInputChannelDetector.cpp + s2e/Plugins/uEmu/DebugPlugin.cpp # Support plugins s2e/Plugins/Support/KeyValueStore.cpp @@ -222,6 +224,7 @@ add_library( s2e/Plugins/Searchers/CUPASearcher.cpp s2e/Plugins/Searchers/SeedSearcher.cpp s2e/Plugins/Searchers/SeedScheduler.cpp + s2e/Plugins/Searchers/ValidPathSearcher.cpp # Function models s2e/Plugins/Models/BaseFunctionModels.cpp diff --git a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp new file mode 100644 index 00000000..041299f4 --- /dev/null +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp @@ -0,0 +1,394 @@ +/// +/// Copyright (C) 2017, Cyberhaven +/// All rights reserved. +/// +/// Licensed under the Cyberhaven Research License Agreement. +/// +#include +#include +#include +#include +#include + +#include "ValidPathSearcher.h" + +namespace s2e { +namespace plugins { + +S2E_DEFINE_PLUGIN(ValidPathSearcher, "ValidPathSearcher S2E plugin", "ValidPathSearcher", "ARMFunctionMonitor"); + +class ValidPathSearcherState : public PluginState { +private: + uint32_t m_stateCallerPC; + uint32_t m_stateReturnPC; + uint64_t m_stateTbNum; + std::pair m_lstFork; + std::vector m_callStk; + +public: + ValidPathSearcherState() : m_stateTbNum(0) { + } + virtual ~ValidPathSearcherState() { + } + static PluginState *factory(Plugin *, S2EExecutionState *) { + return new ValidPathSearcherState(); + } + ValidPathSearcherState *clone() const { + return new ValidPathSearcherState(*this); + } + + inline uint32_t getStateCallerPC() const { + return m_stateCallerPC; + } + inline void setStateCallerPC(uint32_t callerPC) { + m_stateCallerPC = callerPC; + } + + inline uint32_t getStateReturnPC() const { + return m_stateReturnPC; + } + inline void setStateReturnPC(uint32_t returnPC) { + m_stateReturnPC = returnPC; + } + + inline uint64_t getStateTbNum() const { + return m_stateTbNum; + } + inline void incStateTbNum() { + m_stateTbNum++; + } + + inline uint32_t getLastForkCallerPC() const { + return m_lstFork.first; + }; + inline uint32_t getLastForkForkPC() const { + return m_lstFork.second; + }; + inline void setLastFork(uint32_t callerPc, uint32_t forkPc) { + m_lstFork = {callerPc, forkPc}; + }; + + inline std::vector getCallStack() const { + return m_callStk; + } + inline uint32_t sizeCallStack() const { + return m_callStk.size(); + } + inline uint32_t topCallstack() const { + return m_callStk.back(); + } + inline void pushCallStack(uint32_t callerPC) { + m_callStk.emplace_back(callerPC); + } + inline void popCallStack() { + m_callStk.pop_back(); + } +}; + +void ValidPathSearcher::initialize() { + s2e()->getExecutor()->setSearcher(this); + initConnection(); + m_curState = nullptr; + m_selfSwitch = false; + m_searcherActive = false; +} + +klee::ExecutionState &ValidPathSearcher::selectState() { + getDebugStream() << "selectState " + << "[current stateID: " << m_curState->getID() << "] " + << "\n"; + printStateItems(); + + m_isSelfSwitchedState = false; + const uint32_t tmpId = m_lstStateId; + m_lstStateId = m_curState->getID(); + + if (m_selfSwitch) { + m_selfSwitch = false; + if (m_isSelfSwitchedState) { + if (!selectLastState()) { + m_lstStateId = tmpId; + } + return *m_curState; + } + if (!selectCousinState()) { + m_lstStateId = tmpId; + return *m_curState; + } + return *m_curState; + } + if (selectUnvisitedState() || selectValidState()) { + return *m_curState; + } + getDebugStream() << "no option" + << "\n"; + m_lstStateId = tmpId; + return *m_curState; +} + +void ValidPathSearcher::update(klee::ExecutionState *current, const klee::StateSet &addedStates, + const klee::StateSet &removedStates) { + if (!m_searcherActive) { + m_curState = dynamic_cast(current); + DECLARE_PLUGINSTATE(ValidPathSearcherState, m_curState); + getDebugStream() << "[start stateID: " << m_curState->getID() << "] " + << "\n"; + m_searcherActive = true; + m_idStateMap[m_curState->getID()] = {m_curState, plgState->getStateCallerPC(), 0, VALID, 0}; + } + + for (auto it : removedStates) { + S2EExecutionState *removedState = dynamic_cast(it); + auto found = m_idStateMap.find(removedState->getID()); + if (found != m_idStateMap.end()) { + getDebugStream() << "[invalid stateID: " << found->second.state->getID() << "] " + << "\n"; + m_idStateMap.erase(found); + } + } +} + +bool ValidPathSearcher::empty() { + return false; +} + +void ValidPathSearcher::onStateFork(S2EExecutionState *state, const std::vector &newStates, + const std::vector> &newConditions) { + getDebugStream(state) << "onStateFork" + << "\n"; + DECLARE_PLUGINSTATE(ValidPathSearcherState, state); + const uint64_t stateTbNum = plgState->getStateTbNum(); + const uint32_t callerPC = plgState->getStateCallerPC(); + const uint32_t forkPC = state->regs()->getPc(); + const uint32_t id0 = newStates[0]->getID(); + const uint32_t id1 = newStates[1]->getID(); + plgState->setLastFork(callerPC, forkPC); + getDebugStream(state) << "[callerPC: " << hexval(callerPC) << "] " + << "[forkPC: " << hexval(forkPC) << "] " + << "[stateID: " << state->getID() << "] " + << "\n" + << "\t\t[new stateID: " << id0 << "] " + << "[condition: " << newConditions[0] << "] " + << "\n" + << "\t\t[new stateID: " << id1 << "] " + << "[condition: " << newConditions[1] << "] " + << "\n"; + if (m_switchCnt[callerPC][forkPC] < MAX_SWITCH_CNT) { + m_forkStates[callerPC][forkPC].push_back({id0, id1, plgState->sizeCallStack()}); + m_idStateMap[id0] = {newStates[0], callerPC, forkPC, UNVISITED, stateTbNum}; + m_idStateMap[id1] = {newStates[1], callerPC, forkPC, UNVISITED, stateTbNum}; + m_idStateMap[state->getID()].flag = VALID; + m_isSelfSwitchedState = false; + } +} + +void ValidPathSearcher::onTranslateBlockEnd(ExecutionSignal *signal, S2EExecutionState *state, TranslationBlock *tb, + uint64_t pc, bool isStatic, uint64_t staticTargetPc) { + getDebugStream(state) << "onTranslateBlockEnd" + << "\n"; + DECLARE_PLUGINSTATE(ValidPathSearcherState, state); + plgState->incStateTbNum(); + m_idStateMap[state->getID()].tbNum = plgState->getStateTbNum(); + getDebugStream(state) << "[the number of blocks: " << plgState->getStateTbNum() << "]" + << "\n"; +} + +void ValidPathSearcher::onARMFunctionCall(S2EExecutionState *state, uint32_t pcCaller, uint64_t pcCtxHashVal, + uint32_t pcReturn) { + getDebugStream(state) << "onARMFunctionCall" + << "\n"; + DECLARE_PLUGINSTATE(ValidPathSearcherState, state); + plgState->setStateCallerPC(pcCaller); + m_functionCalRetMap[pcReturn] = pcCaller; + plgState->pushCallStack(pcCaller); + for (const auto &it : plgState->getCallStack()) { + getDebugStream(state) << "[caller pc: " << hexval(it) << "] " + << "\n"; + } + + getDebugStream(state) << "[caller pc: " << hexval(pcCaller) << "] " + << "[return pc: " << hexval(pcReturn) << "] " + << "[pc and context hash: " << hexval(pcCtxHashVal) << "] " + << "\n"; +} + +void ValidPathSearcher::onARMFunctionReturn(S2EExecutionState *state, uint32_t pcReturn) { + // for switch based on level of function. + getDebugStream(state) << "onARMFunctionReturn" + << "\n"; + DECLARE_PLUGINSTATE(ValidPathSearcherState, state); + plgState->setStateReturnPC(pcReturn); + m_curState = state; + const uint32_t callerPC = m_functionCalRetMap[pcReturn]; + getDebugStream(state) << "[caller pc: " << hexval(callerPC) << "] " + << "[return pc: " << hexval(pcReturn) << "] " + << "\n"; + + if (!m_searcherActive) { + plgState->popCallStack(); + return; + } + + const std::vector callStack = plgState->getCallStack(); + if (callStack.size() <= SELF_SWITCH_CALL_STACK_LVL) { + plgState->popCallStack(); + return; + } + const uint32_t targetCallerPc = callStack[callStack.size() - 1 - SELF_SWITCH_CALL_STACK_LVL]; + const uint32_t lstForkCallerPc = plgState->getLastForkCallerPC(); + if (targetCallerPc == lstForkCallerPc) { + m_selfSwitch = true; + triggerSelfSwitch(); + } + plgState->popCallStack(); + return; +} + +void ValidPathSearcher::initConnection() { + m_onStateForkConn = + s2e()->getCorePlugin()->onStateFork.connect(sigc::mem_fun(*this, &ValidPathSearcher::onStateFork)); + m_onTranslateBlockEndConn = s2e()->getCorePlugin()->onTranslateBlockEnd.connect( + sigc::mem_fun(*this, &ValidPathSearcher::onTranslateBlockEnd)); + + onARMFunctionConn = s2e()->getPlugin(); + onARMFunctionConn->onARMFunctionCallEvent.connect(sigc::mem_fun(*this, &ValidPathSearcher::onARMFunctionCall)); + onARMFunctionConn->onARMFunctionReturnEvent.connect(sigc::mem_fun(*this, &ValidPathSearcher::onARMFunctionReturn)); +} + +bool ValidPathSearcher::selectCousinState() { + getDebugStream() << "selectCousinState" + << "\n"; + DECLARE_PLUGINSTATE(ValidPathSearcherState, m_curState); + const uint32_t lstForkCallerPc = plgState->getLastForkCallerPC(); + const uint32_t lstForkForkPc = plgState->getLastForkForkPC(); + for (auto it = m_forkStates[lstForkCallerPc][lstForkForkPc].rbegin(); + it != m_forkStates[lstForkCallerPc][lstForkForkPc].rend(); ++it) { + if (it->id1 == m_curState->getID() && m_idStateMap[it->id2].flag == UNVISITED) { + m_curState = m_idStateMap[it->id2].state; + getDebugStream() << "[switch cousin stateID: " << m_curState->getID() << "] " + << "\n"; + m_isSelfSwitchedState = true; + return true; + } else if (it->id2 == m_curState->getID() && m_idStateMap[it->id1].flag == UNVISITED) { + m_curState = m_idStateMap[it->id1].state; + getDebugStream() << "[switch cousin stateID: " << m_curState->getID() << "] " + << "\n"; + m_isSelfSwitchedState = true; + return true; + } else { + continue; + } + } + getDebugStream() << "no option for select cousin state" + << "\n"; + return false; +} + +bool ValidPathSearcher::selectLastState() { + getDebugStream() << "selectLastState" + << "\n"; + DECLARE_PLUGINSTATE(ValidPathSearcherState, m_curState); + const uint64_t curTbNum = plgState->getStateTbNum(); + if (m_idStateMap[m_lstStateId].flag == VALID) { + DECLARE_PLUGINSTATE(ValidPathSearcherState, m_idStateMap[m_lstStateId].state); + if (plgState->getStateTbNum() <= curTbNum) { + m_curState = m_idStateMap[m_lstStateId].state; + getDebugStream() << "[switch last stateID: " << m_curState->getID() << "] " + << "\n"; + return true; + } + } + getDebugStream() << "no option for select last state" + << "\n"; + return false; +} + +bool ValidPathSearcher::selectUnvisitedState() { + getDebugStream() << "selectUnvisitedState" + << "[current stateID: " << m_curState->getID() << "] " + << "\n"; + for (auto it = m_idStateMap.rbegin(); it != m_idStateMap.rend(); ++it) { + if (m_switchCnt[it->second.callerPC][it->second.forkPC] > MAX_SWITCH_CNT) { + continue; + } + if (it->second.flag == UNVISITED && it->second.state->getID() != m_curState->getID()) { + it->second.flag = VALID; + m_switchCnt[it->second.callerPC][it->second.forkPC]++; + m_curState = it->second.state; + getDebugStream() << "[new selected unvisited stateID: " << m_curState->getID() << "] " + << "\n"; + return true; + } + } + return false; +} + +bool ValidPathSearcher::selectValidState() { + getDebugStream() << "selectValidState" + << "\n"; + for (auto it = m_idStateMap.rbegin(); it != m_idStateMap.rend(); ++it) { + if (m_switchCnt[it->second.callerPC][it->second.forkPC] > MAX_SWITCH_CNT) { + continue; + } + if (it->second.state->getID() != m_curState->getID() && it->second.flag == VALID) { + m_switchCnt[it->second.callerPC][it->second.forkPC]++; + m_curState = it->second.state; + getDebugStream() << "[new selected valid stateID: " << m_curState->getID() << "] " + << "\n"; + return true; + } + } + return false; +} + +void ValidPathSearcher::triggerSelfSwitch() { + getDebugStream() << "triggerSelfSwitch" + << "\n"; + // env->current_tb = nullptr; + // m_curState->jumpToSymbolicCpp(); + // s2e_kvm_flush_disk(); + // S2EExecutionState *nextState = s2e()->getExecutor()->selectNextState(g_s2e_state); + // getDebugStream() << "[next stateID: " << nextState->getID() << "] " + // << "\n"; + + m_curState->yield(); + // s2e()->getExecutor()->validPathSearcherStateSwitchCallback(s2e()->getExecutor()); + // getDebugStream() << "[back]" + // << "\n"; + + // s2e()->getExecutor()->setCpuExitRequest(); + // getDebugStream() << "[g_s2e_state: " << g_s2e_state->getID() << "] " + // << "\n"; +} + +void ValidPathSearcher::printForkStates() { + getDebugStream() << "printForkStates" + << "\n"; + for (const auto &it : m_forkStates) { + getDebugStream() << "[callerPC: " << hexval(it.first) << "] " + << "\n"; + for (const auto &it2 : it.second) { + getDebugStream() << "\t[forkPC: " << hexval(it2.first) << "] " + << "\n"; + for (const auto &it3 : it2.second) { + getDebugStream() << "\t\t[stateID: " << it3.id1 << ", " << it3.id2 << "] " + << "[call stack level: " << it3.callStkLvl << "] " + << "\n"; + } + } + } +} + +void ValidPathSearcher::printStateItems() { + getDebugStream() << "printStateMap" + << "\n"; + for (const auto &it : m_idStateMap) { + getDebugStream() << "[stateID: " << it.second.state->getID() << "] " + << "[forkPC: " << hexval(it.second.forkPC) << "] " + << "[flag: " << it.second.flag << "] " + << "\n"; + } +} + +} // namespace plugins +} // namespace s2e diff --git a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h new file mode 100644 index 00000000..6c259478 --- /dev/null +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h @@ -0,0 +1,106 @@ +/// +/// Copyright (C) 2010-2013, Dependable Systems Laboratory, EPFL +/// All rights reserved. +/// +/// Licensed under the Cyberhaven Research License Agreement. +/// + +#ifndef S2E_PLUGINS_VALIDPATHSEARCHER_H +#define S2E_PLUGINS_VALIDPATHSEARCHER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace s2e { +namespace plugins { +using PerifAddr = uint32_t; +using PC = uint32_t; +using PCCtxHash = uint64_t; +using PerifVal = uint32_t; +using PerifSize = uint32_t; + +struct StateItem { + S2EExecutionState *state; + uint32_t callerPC; + uint32_t forkPC; + uint32_t flag; + uint64_t tbNum; +}; + +struct ForkStateInfo { + uint32_t id1; + uint32_t id2; + uint32_t callStkLvl; +}; + +enum StatePhase { UNVISITED, INVALID, VALID }; +const int MAX_SWITCH_CNT = 10; +const int SELF_SWITCH_CALL_STACK_LVL = 2; + +class ValidPathSearcher : public Plugin, public klee::Searcher { + S2E_PLUGIN + +public: + ValidPathSearcher(S2E *s2e) : Plugin(s2e) { + } + + void initialize(); + +private: + sigc::connection m_onStateForkConn; + sigc::connection m_onTranslateBlockEndConn; + ARMFunctionMonitor *onARMFunctionConn; + + uint32_t m_lstStateId; + S2EExecutionState *m_curState; + bool m_selfSwitch; + bool m_isSelfSwitchedState; + bool m_searcherActive; + + std::map>> m_forkStates; + std::map> m_switchCnt; + std::map m_idStateMap; + std::map m_functionCalRetMap; + + void initConnection(); + bool selectCousinState(); + bool selectLastState(); + bool selectUnvisitedState(); + bool selectValidState(); + + void triggerSelfSwitch(); + + void printForkStates(); + void printStateItems(); + + // callbacks + void onStateFork(S2EExecutionState *state, const std::vector &newStates, + const std::vector> &newConditions); + void onTranslateBlockEnd(ExecutionSignal *signal, S2EExecutionState *state, TranslationBlock *tb, uint64_t pc, + bool isStatic, uint64_t staticTargetPc); + void onARMFunctionCall(S2EExecutionState *state, uint32_t pcCaller, uint64_t pcCtxHashVal, uint32_t pcReturn); + void onARMFunctionReturn(S2EExecutionState *state, uint32_t pcReturn); + +public: + virtual klee::ExecutionState &selectState(); + virtual void update(klee::ExecutionState *current, const klee::StateSet &addedStates, + const klee::StateSet &removedStates); + virtual bool empty(); +}; + +} // namespace plugins +} // namespace s2e + +#endif // S2E_PLUGINS_VALIDPATHSEARCHER_H diff --git a/libs2eplugins/src/s2e/Plugins/SymbolicHardware/SymbolicHardware.cpp b/libs2eplugins/src/s2e/Plugins/SymbolicHardware/SymbolicHardware.cpp index c863f8ab..f6da3d5f 100644 --- a/libs2eplugins/src/s2e/Plugins/SymbolicHardware/SymbolicHardware.cpp +++ b/libs2eplugins/src/s2e/Plugins/SymbolicHardware/SymbolicHardware.cpp @@ -256,8 +256,9 @@ klee::ref SymbolicHardware::onReadPeripheral(S2EExecutionState *stat ss << hexval(address) << "@" << hexval(state->regs()->getPc()); - bool createSymFlag = false; + bool createSymFlag = true; uint32_t hwModelValue = concreteValue; + // TOSEE: pt1 onSymbolicRegisterReadEvent.emit(state, type, address, size, &hwModelValue, &createSymFlag, &ss); getDebugStream(g_s2e_state) << ss.str() << " size " << hexval(size) << " value =" << hexval(concreteValue) diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/ARMFunctionMonitor.cpp b/libs2eplugins/src/s2e/Plugins/uEmu/ARMFunctionMonitor.cpp index f3b68fd7..824251cf 100755 --- a/libs2eplugins/src/s2e/Plugins/uEmu/ARMFunctionMonitor.cpp +++ b/libs2eplugins/src/s2e/Plugins/uEmu/ARMFunctionMonitor.cpp @@ -188,7 +188,7 @@ void ARMFunctionMonitor::onFunctionCall(S2EExecutionState *state, uint64_t calle if (function_map.find(caller_pc) == function_map.end()) { function_map[caller_pc] = return_address; } - onARMFunctionCallEvent.emit(state, caller_pc, sum_hash); + onARMFunctionCallEvent.emit(state, caller_pc, sum_hash, return_address); } void ARMFunctionMonitor::onFunctionReturn(S2EExecutionState *state, uint64_t return_pc) { diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/ARMFunctionMonitor.h b/libs2eplugins/src/s2e/Plugins/uEmu/ARMFunctionMonitor.h index be215709..8ee073d2 100755 --- a/libs2eplugins/src/s2e/Plugins/uEmu/ARMFunctionMonitor.h +++ b/libs2eplugins/src/s2e/Plugins/uEmu/ARMFunctionMonitor.h @@ -37,7 +37,8 @@ class ARMFunctionMonitor : public Plugin { sigc::signal onARMFunctionReturnEvent; - sigc::signal + sigc::signal onARMFunctionCallEvent; private: diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp new file mode 100644 index 00000000..f22522aa --- /dev/null +++ b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp @@ -0,0 +1,392 @@ +/// +/// Copyright (C) 2017, Cyberhaven +/// All rights reserved. +/// +/// Licensed under the Cyberhaven Research License Agreement. +/// +#include +#include +#include +#include +#include + +#include "DataInputChannelDetector.h" + +using namespace klee; + +namespace s2e { +namespace plugins { + +static const boost::regex PeripheralModelLearningRegEx("v\\d+_iommuread_(.+)_(.+)_(.+)", boost::regex::perl); +S2E_DEFINE_PLUGIN(DataInputChannelDetector, "DataInputChannelDetector S2E plugin", "DataInputChannelDetector", + "SymbolicHardware"); + +class DataInputChannelDetectorState : public PluginState { +private: + ReadPerifMap m_readPerifSizeMap; + +public: + DataInputChannelDetectorState() { + } + virtual ~DataInputChannelDetectorState() { + } + + static PluginState *factory(Plugin *, S2EExecutionState *) { + return new DataInputChannelDetectorState(); + } + + DataInputChannelDetectorState *clone() const { + return new DataInputChannelDetectorState(*this); + } + + // setter, getter etc. + ReadPerifMap getReadPerifSizeMap() { + return m_readPerifSizeMap; + } + + uint32_t getSizeReadPerifSizeMap(uint32_t perifAddr) { + return m_readPerifSizeMap[perifAddr].first; + } + + uint64_t getCntReadPerifSizeMap(uint32_t perifAddr) { + return m_readPerifSizeMap[perifAddr].second; + } + + void incReadPerifSizeMap(uint32_t perifAddr, uint32_t size) { + m_readPerifSizeMap[perifAddr].first = size; + m_readPerifSizeMap[perifAddr].second++; + } +}; + +void DataInputChannelDetector::initialize() { + + m_symbolicHardwareConn = s2e()->getPlugin(); + m_symbolicHardwareConn->onSymbolicRegisterReadEvent.connect( + sigc::mem_fun(*this, &DataInputChannelDetector::onMMIORead)); + + m_onStateForkConn = + s2e()->getCorePlugin()->onStateFork.connect(sigc::mem_fun(*this, &DataInputChannelDetector::onStateFork)); + m_onSymbolicDataAccessConcreteMemoryConn = s2e()->getCorePlugin()->onSymbolicDataAccessConcreteMemory.connect( + sigc::mem_fun(*this, &DataInputChannelDetector::onSymbolicDataAccessConcreteMemory)); + m_onBeforeSymbolicDataMemoryAccessConn = s2e()->getCorePlugin()->onBeforeSymbolicDataMemoryAccess.connect( + sigc::mem_fun(*this, &DataInputChannelDetector::onBeforeSymbolicDataMemoryAccess)); +} + +void DataInputChannelDetector::onMMIORead(S2EExecutionState *state, SymbolicHardwareAccessType type, uint32_t perifAddr, + unsigned perifSize, uint32_t *val, bool *perifFlag, std::stringstream *ss) { + uint32_t pc = state->regs()->getPc(); + + // record all read phs + DECLARE_PLUGINSTATE(DataInputChannelDetectorState, state); + plgState->incReadPerifSizeMap(perifAddr, perifSize); + + if (state->regs()->getInterruptFlag() && state->regs()->getExceptionIndex() > 15) { + // external irq handle + getDebugStream() << "[DataInputChannelDetector] MMIO read in external IRQ: " + << "[peripheral address: " << hexval(perifAddr) << "] " + << "[pc: " << hexval(pc) << "] " + << "[value: " << hexval(*val) << "] " + << "\n"; + m_IRQMMIOReadPerifPCToPerifSizeSetMap[perifAddr][pc].insert(perifSize); + } + for (const auto &it : m_IRQMMIOReadPerifPCToPerifSizeSetMap) { + for (const auto &it2 : it.second) { + getDebugStream() << "[DataInputChannelDetector] All peripherals read in IRQ: " + << "[peripheral address: " << hexval(it.first) << "] " + << "[pc: " << hexval(it2.first) << "] " + << "\n"; + for (const auto &it3 : it2.second) { + getDebugStream() << "[data size: " << it3 << "] " + << "\n"; + } + } + } +} + +void DataInputChannelDetector::onSymbolicDataAccessConcreteMemory(S2EExecutionState *state, uint64_t concreteAddr, + klee::ref symbVal, bool isWrite) { + getDebugStream() << "[DataInputChannelDetector] onSymbolicDataAccessConcreteMemory" + << "[concrete address: " << hexval(concreteAddr) << "] " + << "[symbolic value: " << symbVal << "] " + << "\n"; + + DECLARE_PLUGINSTATE(DataInputChannelDetectorState, state); + ReadPerifMap curStateReadPerifSizeMap = plgState->getReadPerifSizeMap(); + ArrayVec results; + findSymbolicObjects(symbVal, results); + getDebugStream() << "[size of results: " << results.size() << "] " + << "\n"; + for (int i = results.size() - 1; i >= 0; --i) { + uint32_t perifAddr; + uint32_t pc; + uint64_t hashVal; + uint64_t no; + auto &result = results[i]; + std::vector data; + + getPeripheralExecutionState(result->getName(), &perifAddr, &pc, &hashVal, &no); + + for (unsigned s = 0; s < result->getSize(); ++s) { + ref e = state->concolics->evaluate(result, s); + if (!isa(e)) { + getWarningsStream() << "Failed to evaluate concrete value\n"; + pabort("Failed to evaluate concrete value"); + } + + uint8_t byteVal = dyn_cast(e)->getZExtValue(); + data.push_back(byteVal); + } + + uint32_t condConcreteVal = + data[0] | ((uint32_t) data[1] << 8) | ((uint32_t) data[2] << 16) | ((uint32_t) data[3] << 24); + + uint64_t LSB = ((uint64_t) 1 << (curStateReadPerifSizeMap[perifAddr].first * 8)); + uint32_t val = condConcreteVal & (LSB - 1); + + getDebugStream() << "solve symbolic value: " + << "[peripheral address: " << hexval(perifAddr) << "]" + << "[pc: " << hexval(pc) << "]" + << "[hash of pc and context: " << hexval(hashVal) << "]" + << "[number of value: " << no << "]" + << "[value: " << hexval(val) << "]" + << "\n"; + identifyTB(perifAddr, pc); + } +} + +void DataInputChannelDetector::onBeforeSymbolicDataMemoryAccess(S2EExecutionState *state, klee::ref addr, + klee::ref val, bool isWrite) { + // for onSymbolicDataAccessConcreteMemory can be emitted +} + +void DataInputChannelDetector::onStateFork(S2EExecutionState *state, const std::vector &newStates, + const std::vector> &newConditions) { + getDebugStream() << "[DataInputChannelDetector] onStateFork" << '\n'; + + // DECLARE_PLUGINSTATE(DataInputChannelDetectorState, state); + + // each new states + for (int k = newStates.size() - 1; k >= 0; --k) { + DECLARE_PLUGINSTATE(DataInputChannelDetectorState, newStates[k]); + ReadPerifMap curStateReadPerifSizeMap = plgState->getReadPerifSizeMap(); + ArrayVec condRegs; + + // each conditional register + findSymbolicObjects(newConditions[0], condRegs); + for (int i = condRegs.size() - 1; i >= 0; --i) { + uint32_t perifAddr; + uint32_t pc; + uint64_t hashVal; + uint64_t no; + auto &condReg = condRegs[i]; + std::vector data; + + getPeripheralExecutionState(condReg->getName(), &perifAddr, &pc, &hashVal, &no); + + for (unsigned s = 0; s < condReg->getSize(); ++s) { + ref e = newStates[k]->concolics->evaluate(condReg, s); + if (!isa(e)) { + getWarningsStream() << "Failed to evaluate concrete value\n"; + pabort("Failed to evaluate concrete value"); + } + + uint8_t byteVal = dyn_cast(e)->getZExtValue(); + data.push_back(byteVal); + } + + uint32_t condConcreteVal = + data[0] | ((uint32_t) data[1] << 8) | ((uint32_t) data[2] << 16) | ((uint32_t) data[3] << 24); + + uint64_t LSB = ((uint64_t) 1 << (curStateReadPerifSizeMap[perifAddr].first * 8)); + uint32_t val = condConcreteVal & (LSB - 1); + + getDebugStream() << "condition register Info: " + << "[peripheral address: " << hexval(perifAddr) << "]" + << "[pc: " << hexval(pc) << "]" + << "[hash of pc and context: " << hexval(hashVal) << "]" + << "[number of value: " << no << "]" + << "[value: " << hexval(val) << "]" + << "\n"; + + // IRQ + if (state->regs()->getInterruptFlag() && state->regs()->getExceptionIndex() > 15) { + // possible CR SR in IRQ + const auto &foundPossCRSR = m_IRQMMIOReadPerifPCToPerifSizeSetMap.find(perifAddr); + if (foundPossCRSR != m_IRQMMIOReadPerifPCToPerifSizeSetMap.end()) { + m_IRQMMIOReadPossCRSR[perifAddr].insert(pc); + getDebugStream() << "found a possible CR/SR peripheral in IRQ: " + << "[peripheral address: " << hexval(perifAddr) << "] " + << "[pc: " << hexval(pc) << "] " + << "\n"; + } + } else { + if (val != 0) { + m_IRQMMIOReadPerifPCToValSetMap[perifAddr][pc].insert(val); + } + identifyTA(perifAddr, pc); + } + } + } + identifyTC(); +} + +void DataInputChannelDetector::identifyTA(const uint32_t &perifAddr, const uint32_t &pc) { + getDebugStream() << "[DataInputChannelDetector] identifyTA " + << "[peripheral address: " << hexval(perifAddr) << "] " + << "[pc: " << hexval(pc) << "] " << '\n'; + const auto &foundPossIRQCRSR = m_IRQMMIOReadPossCRSR.find(perifAddr); + if (foundPossIRQCRSR != m_IRQMMIOReadPossCRSR.end()) { + getDebugStream() << "return, peripheral is a possible CR/SR in IRQ: " << hexval(perifAddr) << '\n'; + return; + } + + const auto &foundSamePerif = m_DRDetected.find(perifAddr); + if (foundSamePerif != m_DRDetected.end()) { + const auto &foundSamePC = m_DRDetected[perifAddr].find(pc); + if (foundSamePC != m_DRDetected[perifAddr].end()) { + getDebugStream() << "return, already identified as DR: " << hexval(perifAddr) << '\n'; + return; + } + m_DRDetected[perifAddr][pc] = m_IRQMMIOReadPerifPCToPerifSizeSetMap[perifAddr][pc]; + getDebugStream() << "Identified by TA: " + << "[peripheral address: " << hexval(perifAddr) << "] " + << "[pc: " << hexval(pc) << "] " + << "\n"; + return; + } + + const auto &foundOverlap = m_IRQMMIOReadPerifPCToPerifSizeSetMap.find(perifAddr); + if (foundOverlap == m_IRQMMIOReadPerifPCToPerifSizeSetMap.end()) { + getDebugStream() << "return, unable to find a overlap: " << hexval(perifAddr) << '\n'; + return; + } + m_DRDetected[perifAddr][pc] = m_IRQMMIOReadPerifPCToPerifSizeSetMap[perifAddr][pc]; + getDebugStream() << "Identified by TA: " + << "[peripheral address: " << hexval(perifAddr) << "] " + << "[pc: " << hexval(pc) << "] " + << "\n"; +} + +void DataInputChannelDetector::identifyTB(const uint32_t &perifAddr, const uint32_t &pc) { + getDebugStream() << "[DataInputChannelDetector] identifyTB " + << "[peripheral address: " << hexval(perifAddr) << "] " + << "[pc: " << hexval(pc) << "] " << '\n'; + const auto &foundPossIRQCRSR = m_IRQMMIOReadPossCRSR.find(perifAddr); + if (foundPossIRQCRSR != m_IRQMMIOReadPossCRSR.end()) { + getDebugStream() << "return, peripheral is a possible CR/SR in IRQ: " << hexval(perifAddr) << '\n'; + return; + } + + const auto &foundSamePerif = m_DRDetected.find(perifAddr); + if (foundSamePerif != m_DRDetected.end()) { + const auto &foundSamePC = m_DRDetected[perifAddr].find(pc); + if (foundSamePC != m_DRDetected[perifAddr].end()) { + getDebugStream() << "return, already identified as DR: " << hexval(perifAddr) << '\n'; + return; + } + m_DRDetected[perifAddr][pc] = m_IRQMMIOReadPerifPCToPerifSizeSetMap[perifAddr][pc]; + getDebugStream() << "Identified by TB: " + << "[peripheral address: " << hexval(perifAddr) << "] " + << "[pc: " << hexval(pc) << "] " + << "\n"; + return; + } + + const auto &foundOverlap = m_IRQMMIOReadPerifPCToPerifSizeSetMap.find(perifAddr); + if (foundOverlap == m_IRQMMIOReadPerifPCToPerifSizeSetMap.end()) { + getDebugStream() << "return, unable to find a overlap: " << hexval(perifAddr) << '\n'; + return; + } + m_DRDetected[perifAddr][pc] = m_IRQMMIOReadPerifPCToPerifSizeSetMap[perifAddr][pc]; + getDebugStream() << "Identified by TB: " + << "[peripheral address: " << hexval(perifAddr) << "] " + << "[pc: " << hexval(pc) << "] " + << "\n"; +} + +void DataInputChannelDetector::identifyTC() { + getDebugStream() << "[DataInputChannelDetector] identifyTC" << '\n'; + for (const auto &it : m_IRQMMIOReadPerifPCToValSetMap) { + const auto &foundPossIRQCRSR = m_IRQMMIOReadPossCRSR.find(it.first); + if (foundPossIRQCRSR != m_IRQMMIOReadPossCRSR.end()) { + getDebugStream() << "continue, peripheral is a possible CR/SR in IRQ: " << hexval(it.first) << '\n'; + continue; + } + getDebugStream() << "[peripheral address: " << hexval(it.first) << "] " + << "\n"; + for (const auto &it2 : it.second) { + const auto &foundSamePerif = m_DRDetected.find(it.first); + if (foundSamePerif != m_DRDetected.end()) { + const auto &foundSamePC = m_DRDetected[it.first].find(it2.first); + if (foundSamePC != m_DRDetected[it.first].end()) { + getDebugStream() << "continue, already identified as DR: " << hexval(it.first) << '\n'; + continue; + } + } + + getDebugStream() << "[pc: " << hexval(it2.first) << "] " + << "[same pc count: " << it2.second.size() << "] " + << "\n"; + if (it2.second.size() < 2) { + continue; + } + for (const auto &it3 : it2.second) { + getDebugStream() << "[value: " << hexval(it3) << "] "; + } + getDebugStream() << "\n"; + if (it2.second.size() > 3) { + m_DRDetected[it.first][it2.first] = m_IRQMMIOReadPerifPCToPerifSizeSetMap[it.first][it2.first]; + getDebugStream() << "Identified by TC: " + << "[peripheral address: " << hexval(it.first) << "] " + << "\n"; + } + } + } +} + +bool DataInputChannelDetector::getPeripheralExecutionState(std::string perifName, uint32_t *perifAddr, uint32_t *pc, + uint64_t *hashVal, uint64_t *no) { + boost::smatch what; + if (!boost::regex_match(perifName, what, PeripheralModelLearningRegEx)) { + getWarningsStream() << "match false" + << "\n"; + exit(0); + return false; + } + + if (what.size() != 4) { + getWarningsStream() << "wrong size = " << what.size() << "\n"; + exit(0); + return false; + } + + std::string perifAddrPCStr = what[1]; + std::string hashValStr = what[2]; + std::string noStr = what[3]; + + std::vector v; + splitString(perifAddrPCStr, v, "_"); + *perifAddr = std::stoull(v[0].c_str(), NULL, 16); + *pc = std::stoull(v[1].c_str(), NULL, 16); + *hashVal = std::stoull(hashValStr.c_str(), NULL, 16); + *no = std::stoull(noStr.c_str(), NULL, 10); + + return true; +} + +void DataInputChannelDetector::splitString(const std::string &s, std::vector &v, const std::string &c) { + std::string::size_type pos1, pos2; + pos2 = s.find(c); + pos1 = 0; + while (std::string::npos != pos2) { + v.push_back(s.substr(pos1, pos2 - pos1)); + + pos1 = pos2 + c.size(); + pos2 = s.find(c, pos1); + } + if (pos1 != s.length()) + v.push_back(s.substr(pos1)); +} + +} // namespace plugins +} // namespace s2e diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h new file mode 100644 index 00000000..83c2f227 --- /dev/null +++ b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h @@ -0,0 +1,136 @@ +/// +/// Copyright (C) 2010-2013, Dependable Systems Laboratory, EPFL +/// All rights reserved. +/// +/// Licensed under the Cyberhaven Research License Agreement. +/// + +#ifndef S2E_PLUGINS_DATAINPUTCHANNELDETECTOR_H +#define S2E_PLUGINS_DATAINPUTCHANNELDETECTOR_H + +#include +#include +#include +#include + +namespace s2e { +namespace plugins { +using PerifAddr = uint32_t; +using PC = uint32_t; +using PCCtxHash = uint64_t; +using PerifVal = uint32_t; +using PerifSize = uint32_t; + +using ReadPerifMap = std::map>; +using PerifAddrPerifSizeMap = std::map; + +using PerifAddrToPCSetMap = std::map>; +using PerifAddrPCToPerifSizeSetMap = std::map>>; +using PerifAddrPCToValSetMap = std::map>>; + +class DataInputChannelDetector : public Plugin { + S2E_PLUGIN + +public: + DataInputChannelDetector(S2E *s2e) : Plugin(s2e) { + } + + void initialize(); + +private: + sigc::connection m_onStateForkConn; + sigc::connection m_onSymbolicDataAccessConcreteMemoryConn; + sigc::connection m_onBeforeSymbolicDataMemoryAccessConn; + hw::SymbolicHardware *m_symbolicHardwareConn; + + PerifAddrPCToPerifSizeSetMap m_DRDetected; + + PerifAddrPCToPerifSizeSetMap m_IRQMMIOReadPerifPCToPerifSizeSetMap; + PerifAddrPCToValSetMap m_IRQMMIOReadPerifPCToValSetMap; // not store 0 + PerifAddrToPCSetMap m_IRQMMIOReadPossCRSR; + + /** + * Get peripheral info from execution state. + * + * @param perifEntry a entry of peripheral + * @param perifAddr address of peripheral + * @param pc address of pc + * @param hashVal hash of pc and context + * @param no the number of value + * @return return true if get peripheral info successfully + */ + bool getPeripheralExecutionState(std::string perifEntry, uint32_t *perifAddr, uint32_t *pc, uint64_t *hashVal, + uint64_t *no); + + /** + * + * @param s source string + * @param v string vector of destination strings + * @param c string of delimiter + */ + void splitString(const std::string &s, std::vector &d, const std::string &c); + + /** + * identify TA DR. + * + * @param perifAddr peripheral address + * @param pc pc address + */ + void identifyTA(const uint32_t &perifAddr, const uint32_t &pc); + + /** + * identify TB DR. + * + * @param perifAddr peripheral address + * @param pc pc address + */ + void identifyTB(const uint32_t &perifAddr, const uint32_t &pc); + + /** + * identify TC DR. + * + */ + void identifyTC(); + +public: + /** + * callback for peripheral MMIO read + * @param state s2e state + * @param type + * @param perifAddr address of peripheral + * @param perifSize data size of peripheral + * @param val value + * @param perifFlag flag of peripheral + * @param ss + */ + void onMMIORead(S2EExecutionState *state, SymbolicHardwareAccessType type, uint32_t perifAddr, unsigned perifSize, + uint32_t *val, bool *perifFlag, std::stringstream *ss); + + /** + * callback for symbolic data access concrete memory. + * + * @param state s2e state + * @param concreteAddr concrete address + * @param symbVal symbolic data + * @param isWrite whether write or not + */ + void onSymbolicDataAccessConcreteMemory(S2EExecutionState *state, uint64_t concreteAddr, + klee::ref symbVal, bool isWrite); + + void onBeforeSymbolicDataMemoryAccess(S2EExecutionState *state, klee::ref addr, + klee::ref val, bool isWrite); + + /** + * callback when state fork + * @param state + * @param newStates + * @param newConditions + */ + void onStateFork(S2EExecutionState *state, const std::vector &newStates, + const std::vector> &newConditions); +}; + +} // namespace plugins +} // namespace s2e + +#endif // S2E_PLUGINS_DATAINPUTCHANNELDETECTOR_H diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/DebugPlugin.cpp b/libs2eplugins/src/s2e/Plugins/uEmu/DebugPlugin.cpp new file mode 100644 index 00000000..f7af9219 --- /dev/null +++ b/libs2eplugins/src/s2e/Plugins/uEmu/DebugPlugin.cpp @@ -0,0 +1,134 @@ +/// +/// Copyright (C) 2017, Cyberhaven +/// All rights reserved. +/// +/// Licensed under the Cyberhaven Research License Agreement. +/// +#include +#include +#include +#include +#include + +#include "DebugPlugin.h" + +using namespace klee; + +namespace s2e { +namespace plugins { + +static const boost::regex PeripheralModelLearningRegEx("v\\d+_iommuread_(.+)_(.+)_(.+)", boost::regex::perl); +S2E_DEFINE_PLUGIN(DebugPlugin, "DebugPlugin S2E plugin", "DebugPlugin", "SymbolicHardware"); + +class DebugPluginState : public PluginState { +private: + ReadPerifMap m_readPerifSizeMap; + +public: + DebugPluginState() { + } + virtual ~DebugPluginState() { + } + + static PluginState *factory(Plugin *, S2EExecutionState *) { + return new DebugPluginState(); + } + + DebugPluginState *clone() const { + return new DebugPluginState(*this); + } +}; + +void DebugPlugin::initialize() { + + m_symbolicHardwareConn = s2e()->getPlugin(); + m_symbolicHardwareConn->onSymbolicRegisterReadEvent.connect(sigc::mem_fun(*this, &DebugPlugin::onMMIORead)); + + m_onStateForkConn = s2e()->getCorePlugin()->onStateFork.connect(sigc::mem_fun(*this, &DebugPlugin::onStateFork)); + m_onSymbolicDataAccessConcreteMemoryConn = s2e()->getCorePlugin()->onSymbolicDataAccessConcreteMemory.connect( + sigc::mem_fun(*this, &DebugPlugin::onSymbolicDataAccessConcreteMemory)); + m_onBeforeSymbolicDataMemoryAccessConn = s2e()->getCorePlugin()->onBeforeSymbolicDataMemoryAccess.connect( + sigc::mem_fun(*this, &DebugPlugin::onBeforeSymbolicDataMemoryAccess)); + m_onStateKillConn = s2e()->getCorePlugin()->onStateKill.connect(sigc::mem_fun(*this, &DebugPlugin::onStateKill)); + m_onStateSwitchConn = + s2e()->getCorePlugin()->onStateSwitch.connect(sigc::mem_fun(*this, &DebugPlugin::onStateSwitch)); +} + +void DebugPlugin::onMMIORead(S2EExecutionState *state, SymbolicHardwareAccessType type, uint32_t perifAddr, + unsigned perifSize, uint32_t *val, bool *perifFlag, std::stringstream *ss) { + getDebugStream() << " onMMIORead" + << "\n"; +} + +void DebugPlugin::onSymbolicDataAccessConcreteMemory(S2EExecutionState *state, uint64_t concreteAddr, + klee::ref symbVal, bool isWrite) { + getDebugStream() << " onSymbolicDataAccessConcreteMemory" + << "[concrete address: " << hexval(concreteAddr) << "] " + << "[symbolic value: " << symbVal << "] " + << "\n"; +} + +void DebugPlugin::onBeforeSymbolicDataMemoryAccess(S2EExecutionState *state, klee::ref addr, + klee::ref val, bool isWrite) { + // for onSymbolicDataAccessConcreteMemory can be emitted +} + +void DebugPlugin::onStateFork(S2EExecutionState *state, const std::vector &newStates, + const std::vector> &newConditions) { + getDebugStream() << " onStateFork" << '\n'; +} + +void DebugPlugin::onStateKill(S2EExecutionState *state) { + getDebugStream() << " onStateKill" << '\n'; +} + +void DebugPlugin::onStateSwitch(S2EExecutionState *currentState, S2EExecutionState *nextState) { + getDebugStream() << " onStateSwitch" << '\n'; +} + +bool DebugPlugin::getPeripheralExecutionState(std::string perifName, uint32_t *perifAddr, uint32_t *pc, + uint64_t *hashVal, uint64_t *no) { + boost::smatch what; + if (!boost::regex_match(perifName, what, PeripheralModelLearningRegEx)) { + getWarningsStream() << "match false" + << "\n"; + exit(0); + return false; + } + + if (what.size() != 4) { + getWarningsStream() << "wrong size = " << what.size() << "\n"; + exit(0); + return false; + } + + std::string perifAddrPCStr = what[1]; + std::string hashValStr = what[2]; + std::string noStr = what[3]; + + std::vector v; + splitString(perifAddrPCStr, v, "_"); + *perifAddr = std::stoull(v[0].c_str(), NULL, 16); + *pc = std::stoull(v[1].c_str(), NULL, 16); + *hashVal = std::stoull(hashValStr.c_str(), NULL, 16); + *no = std::stoull(noStr.c_str(), NULL, 10); + + return true; +} + +void DebugPlugin::splitString(const std::string &s, std::vector &v, const std::string &c) { + std::string::size_type pos1, pos2; + pos2 = s.find(c); + pos1 = 0; + while (std::string::npos != pos2) { + v.push_back(s.substr(pos1, pos2 - pos1)); + + pos1 = pos2 + c.size(); + pos2 = s.find(c, pos1); + } + if (pos1 != s.length()) + v.push_back(s.substr(pos1)); +} + +} // namespace plugins +} // namespace s2e diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/DebugPlugin.h b/libs2eplugins/src/s2e/Plugins/uEmu/DebugPlugin.h new file mode 100644 index 00000000..0a5806f9 --- /dev/null +++ b/libs2eplugins/src/s2e/Plugins/uEmu/DebugPlugin.h @@ -0,0 +1,126 @@ +/// +/// Copyright (C) 2010-2013, Dependable Systems Laboratory, EPFL +/// All rights reserved. +/// +/// Licensed under the Cyberhaven Research License Agreement. +/// + +#ifndef S2E_PLUGINS_DATAINPUTCHANNELDETECTOR_H +#define S2E_PLUGINS_DEBUGPLUGIN_H + +#include +#include +#include +#include + +namespace s2e { +namespace plugins { +using PerifAddr = uint32_t; +using PC = uint32_t; +using PCCtxHash = uint64_t; +using PerifVal = uint32_t; +using PerifSize = uint32_t; + +using ReadPerifMap = std::map>; +using PerifAddrPerifSizeMap = std::map; + +using PerifAddrToPCSetMap = std::map>; +using PerifAddrPCToPerifSizeSetMap = std::map>>; +using PerifAddrPCToValSetMap = std::map>>; + +class DebugPlugin : public Plugin { + S2E_PLUGIN + +public: + DebugPlugin(S2E *s2e) : Plugin(s2e) { + } + + void initialize(); + +private: + sigc::connection m_onStateForkConn; + sigc::connection m_onSymbolicDataAccessConcreteMemoryConn; + sigc::connection m_onBeforeSymbolicDataMemoryAccessConn; + sigc::connection m_onStateKillConn; + sigc::connection m_onStateSwitchConn; + + hw::SymbolicHardware *m_symbolicHardwareConn; + + /** + * Get peripheral info from execution state. + * + * @param perifEntry a entry of peripheral + * @param perifAddr address of peripheral + * @param pc address of pc + * @param hashVal hash of pc and context + * @param no the number of value + * @return return true if get peripheral info successfully + */ + bool getPeripheralExecutionState(std::string perifEntry, uint32_t *perifAddr, uint32_t *pc, uint64_t *hashVal, + uint64_t *no); + + /** + * + * @param s source string + * @param v string vector of destination strings + * @param c string of delimiter + */ + void splitString(const std::string &s, std::vector &d, const std::string &c); + +public: + /** + * callback for peripheral MMIO read + * @param state s2e state + * @param type + * @param perifAddr address of peripheral + * @param perifSize data size of peripheral + * @param val value + * @param perifFlag flag of peripheral + * @param ss + */ + void onMMIORead(S2EExecutionState *state, SymbolicHardwareAccessType type, uint32_t perifAddr, unsigned perifSize, + uint32_t *val, bool *perifFlag, std::stringstream *ss); + + /** + * callback for symbolic data access concrete memory. + * + * @param state s2e state + * @param concreteAddr concrete address + * @param symbVal symbolic data + * @param isWrite whether write or not + */ + void onSymbolicDataAccessConcreteMemory(S2EExecutionState *state, uint64_t concreteAddr, + klee::ref symbVal, bool isWrite); + + void onBeforeSymbolicDataMemoryAccess(S2EExecutionState *state, klee::ref addr, + klee::ref val, bool isWrite); + + /** + * callback when state fork. + * @param state + * @param newStates + * @param newConditions + */ + void onStateFork(S2EExecutionState *state, const std::vector &newStates, + const std::vector> &newConditions); + + /** + * callback when state kill. + * + * @param state + */ + void onStateKill(S2EExecutionState *state); + + /** + * callback when state switch. + * + * @param currentState + * @param nextState + */ + void onStateSwitch(S2EExecutionState *currentState, S2EExecutionState *nextState); +}; + +} // namespace plugins +} // namespace s2e + +#endif // S2E_PLUGINS_DEBUGPLUGIN_H diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/PeripheralModelLearning.cpp b/libs2eplugins/src/s2e/Plugins/uEmu/PeripheralModelLearning.cpp index 530bb14c..719812b8 100755 --- a/libs2eplugins/src/s2e/Plugins/uEmu/PeripheralModelLearning.cpp +++ b/libs2eplugins/src/s2e/Plugins/uEmu/PeripheralModelLearning.cpp @@ -1924,7 +1924,7 @@ void PeripheralModelLearning::saveKBtoFile(S2EExecutionState *state, uint64_t tb getInfoStream(state) << "=========KB Extraction Phase Finish===========\n"; } -void PeripheralModelLearning::onARMFunctionCall(S2EExecutionState *state, uint32_t caller_pc, uint64_t function_hash) { +void PeripheralModelLearning::onARMFunctionCall(S2EExecutionState *state, uint32_t caller_pc, uint64_t function_hash, uint32_t return_pc) { DECLARE_PLUGINSTATE(PeripheralModelLearningState, state); if (state->regs()->getInterruptFlag()) { if (state->regs()->getExceptionIndex() > 15 && !g_s2e_cache_mode) { diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/PeripheralModelLearning.h b/libs2eplugins/src/s2e/Plugins/uEmu/PeripheralModelLearning.h index eac0a801..9258094d 100755 --- a/libs2eplugins/src/s2e/Plugins/uEmu/PeripheralModelLearning.h +++ b/libs2eplugins/src/s2e/Plugins/uEmu/PeripheralModelLearning.h @@ -195,7 +195,7 @@ class PeripheralModelLearning : public Plugin { void onSymbolicAddress(S2EExecutionState *state, klee::ref virtualAddress, uint64_t concreteAddress, bool &concretize, CorePlugin::symbolicAddressReason reason); void onARMFunctionReturn(S2EExecutionState *state, uint32_t return_pc); - void onARMFunctionCall(S2EExecutionState *state, uint32_t caller_pc, uint64_t function_hash); + void onARMFunctionCall(S2EExecutionState *state, uint32_t caller_pc, uint64_t function_hash, uint32_t return_pc); }; diff --git a/scripts/determine_clang_binary_suffix.py b/scripts/determine_clang_binary_suffix.py index 74ee79f8..4769ef37 100755 --- a/scripts/determine_clang_binary_suffix.py +++ b/scripts/determine_clang_binary_suffix.py @@ -51,7 +51,7 @@ def _get_debian_version(version_string): version = int(version_string) if version >= 8: - return 'x86_64-linux-gnu-debian8' + return 'x86_64-linux-gnu-ubuntu-18.04' else: return None @@ -63,8 +63,6 @@ def _get_ubuntu_version(version_string): """ major_version, minor_version = list(map(int, version_string.split('.'))) - # Currently S2E only supports LLVM 3.9.1, and the only Clang binary - # packages that exist for this version are for Ubuntu 14.04 and 16.04 if major_version == 14 and minor_version >= 4: return 'x86_64-linux-gnu-ubuntu-14.04', elif major_version == 15: @@ -75,13 +73,16 @@ def _get_ubuntu_version(version_string): return 'x86_64-linux-gnu-ubuntu-18.04', elif major_version == 20: return 'x86_64-linux-gnu-ubuntu-18.04', + elif major_version == 22: + return 'x86_64-linux-gnu-ubuntu-18.04', else: return None def main(): """The main function.""" - name, version, _ = distro.linux_distribution() + name = distro.id() + version = distro.version() clang_ver_to_download = None @@ -101,4 +102,4 @@ def main(): if __name__ == '__main__': - main() + main() \ No newline at end of file