From a2267edbc16e6cc1c820b8d09c71b8171abe2b8f Mon Sep 17 00:00:00 2001 From: hwk2077 Date: Sun, 19 Mar 2023 17:37:54 +0800 Subject: [PATCH 01/15] init commit. --- libs2eplugins/src/CMakeLists.txt | 1 + .../Plugins/uEmu/DataInputChannelDetector.cpp | 60 +++++++++++++++++++ .../Plugins/uEmu/DataInputChannelDetector.h | 60 +++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp create mode 100644 libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h diff --git a/libs2eplugins/src/CMakeLists.txt b/libs2eplugins/src/CMakeLists.txt index 32eaeb9c..11faa988 100644 --- a/libs2eplugins/src/CMakeLists.txt +++ b/libs2eplugins/src/CMakeLists.txt @@ -172,6 +172,7 @@ add_library( s2e/Plugins/uEmu/uEmuExternalInterrupt.cpp s2e/Plugins/uEmu/ARMFunctionMonitor.cpp s2e/Plugins/uEmu/InvalidStatesDetection.cpp + s2e/Plugins/uEmu/DataInputChannelDetector.cpp # Support plugins s2e/Plugins/Support/KeyValueStore.cpp diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp new file mode 100644 index 00000000..262f457e --- /dev/null +++ b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp @@ -0,0 +1,60 @@ +/// +/// Copyright (C) 2017, Cyberhaven +/// All rights reserved. +/// +/// Licensed under the Cyberhaven Research License Agreement. +/// + +#include +#include +#include + +#include "DataInputChannelDetector.h" + +namespace s2e { +namespace plugins { + +S2E_DEFINE_PLUGIN(DataInputChannelDetector, "DataInputChannelDetector S2E plugin", "DataInputChannelDetector", + "SymbolicHardware"); + +class DataInputChannelDetectorState : public PluginState { +public: + DataInputChannelDetectorState() { + } + virtual ~DataInputChannelDetectorState() { + } + + static PluginState *factory(Plugin *, S2EExecutionState *) { + return new DataInputChannelDetectorState(); + } + + DataInputChannelDetectorState *clone() const { + return new DataInputChannelDetectorState(*this); + } +}; + +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)); +} + +void DataInputChannelDetector::onMMIORead(S2EExecutionState *state, SymbolicHardwareAccessType type, uint32_t perifAddr, + unsigned perifSize, uint32_t *symbVal, bool *perifFlag, + std::stringstream *ss) { + // DECLARE_PLUGINSTATE(DataInputChannelDetectorState, state); + s2e()->getDebugStream() << "dicd: onMMIORead" << '\n'; +} + +void DataInputChannelDetector::onStateFork(S2EExecutionState *state, const std::vector &newStates, + const std::vector> &newConditions) { + // DECLARE_PLUGINSTATE(DataInputChannelDetectorState, state); + s2e()->getDebugStream() << "dicd: onStateFork" << '\n'; +} + +} // 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..b419c4c3 --- /dev/null +++ b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h @@ -0,0 +1,60 @@ +/// +/// 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 { +enum DataRegisterType { TA, TB, TC, TD }; + +class DataInputChannelDetector : public Plugin { + S2E_PLUGIN + +public: + DataInputChannelDetector(S2E *s2e) : Plugin(s2e) { + } + + void initialize(); + +private: + sigc::connection m_onStateForkConn; + hw::SymbolicHardware *m_symbolicHardwareConn; + +public: + /** + * callback for peripheral MMIO read + * @param state s2e state + * @param type + * @param perifAddr address of peripheral + * @param perifSize data size of peripheral + * @param symbVal symbolic value + * @param perifFlag flag of peripheral + * @param ss + */ + void onMMIORead(S2EExecutionState *state, SymbolicHardwareAccessType type, uint32_t perifAddr, unsigned perifSize, + uint32_t *symbVal, bool *perifFlag, std::stringstream *ss); + + /** + * 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 From f979f98fd80e42f3f606a43c449aec15935e8fc8 Mon Sep 17 00:00:00 2001 From: hwk2077 Date: Wed, 22 Mar 2023 23:00:20 +0800 Subject: [PATCH 02/15] cp data structure from `peripheralLearning` --- .../Plugins/uEmu/DataInputChannelDetector.h | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h index b419c4c3..0765cc52 100644 --- a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h +++ b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h @@ -16,6 +16,70 @@ namespace s2e { namespace plugins { enum DataRegisterType { TA, TB, TC, TD }; +enum PeripheralRegisterType { TIRQS, TIRQC, T0, T1, PT1, T2, T3 }; +enum KBUpdateReason { Valid, Invlid }; + +// For General Peripheral in KB: T0~T3 +using PerifAddr = uint32_t; +using PCAddr = uint32_t; +using PCCtxHash = uint64_t; +using PerifVal = uint32_t; + +// For IRQ Peripheral in KB: TIRQS TIRQC +using IRQNo = uint32_t; +using CRAddr = uint32_t; +using CRVal = uint32_t; + +// For DR in KB +using PerifSize = uint32_t; + +// util +using PerifPCPair = std::pair; + +using ValNo = uint64_t; +using NoValPair = std::pair; +using NoValMap = std::map; + +using PCCtxHashPerifValMap = std::map; +using PCCtxHashNoValPairMap = std::map; + +using IRQNoPerifAddrPair = std::pair; +using IRQNoPerifPCTuple = std::tuple; +using IRQCRMap = std::map>>; +using IRQSRMap = std::map; + +using T2PerifTuple = std::tuple; + +using ReadPerifMap = std::map>; +using ReadPerifTuple = std::pair>; + +using ConcreteArray = std::vector; + +using PerifAddrPerifSizeMap = std::map; +using PerifAddrPerifValMap = std::map; +using PerifAddrForkCntMap = std::map; +using ForkStateStack = std::vector>; + +// For Flag +using PerifFlag = uint32_t; +using PerifAddrToPerifFlagMap = std::map; +using TIRQPerifToPerifFlagMap = std::map; +using TIRQSPerifToPerifFlagMap = std::map; + +// peripheral Map +using PerifMap = std::map; +using T0PerifMap = std::map>>; +using T1PerifMap = std::map; +using T1BPerifMap = std::map>; +using T1BNPerifMap = std::map>; +using T2PerifMap = std::map; +using T3PerifMap = std::map>; +using TIRQCPerifMap = std::map; +using TIRQSPerifMap = std::map>; + +// KB +using AllKnowledgeBaseMap = std::map; +using AllKnowledgeBaseNoMap = std::map; class DataInputChannelDetector : public Plugin { S2E_PLUGIN From d12a05b864551933355a7ab992fe30fbe2e50a28 Mon Sep 17 00:00:00 2001 From: hwk2077 Date: Thu, 23 Mar 2023 00:23:49 +0800 Subject: [PATCH 03/15] feat: identify TA DR --- libs2e/configure | 0 .../Plugins/uEmu/DataInputChannelDetector.cpp | 99 ++++++++++++++++++- .../Plugins/uEmu/DataInputChannelDetector.h | 32 ++++++ 3 files changed, 126 insertions(+), 5 deletions(-) mode change 100644 => 100755 libs2e/configure diff --git a/libs2e/configure b/libs2e/configure old mode 100644 new mode 100755 diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp index 262f457e..37a050e4 100644 --- a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp +++ b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp @@ -4,16 +4,20 @@ /// /// 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"); @@ -46,14 +50,99 @@ void DataInputChannelDetector::initialize() { void DataInputChannelDetector::onMMIORead(S2EExecutionState *state, SymbolicHardwareAccessType type, uint32_t perifAddr, unsigned perifSize, uint32_t *symbVal, bool *perifFlag, std::stringstream *ss) { - // DECLARE_PLUGINSTATE(DataInputChannelDetectorState, state); - s2e()->getDebugStream() << "dicd: onMMIORead" << '\n'; + // DECLARE_PLUGINSTATE(DataInputChannelDetectorState, state); + s2e()->getDebugStream() << "[DataInputChannelDetector]: onMMIORead" << '\n'; + if (state->regs()->getInterruptFlag() && state->regs()->getExceptionIndex() > 15) { + // external irq handle + s2e()->getDebugStream() << "[DataInputChannelDetector]: MMIO read in external IRQ: " << perifAddr << '\n'; + m_IRQMMIOReadPerif.insert(perifAddr); + } } void DataInputChannelDetector::onStateFork(S2EExecutionState *state, const std::vector &newStates, const std::vector> &newConditions) { - // DECLARE_PLUGINSTATE(DataInputChannelDetectorState, state); - s2e()->getDebugStream() << "dicd: onStateFork" << '\n'; + // DECLARE_PLUGINSTATE(DataInputChannelDetectorState, state); + s2e()->getDebugStream() << "[DataInputChannelDetector]: onStateFork" << '\n'; + + for (int k = newStates.size() - 1; k >= 0; --k) { + // DECLARE_PLUGINSTATE(DataInputChannelDetectorState, newStates[k]); + ArrayVec results; + findSymbolicObjects(newConditions[0], results); + for (int i = results.size() - 1; i >= 0; --i) { + uint32_t perifAddr; + uint32_t pcAddr; + uint64_t hashVal; + uint64_t no; + auto &arr = results[i]; + std::vector data; + getPeripheralExecutionState(arr->getName(), &perifAddr, &pcAddr, &hashVal, &no); + s2e()->getDebugStream() << "[DataInputChannelDetector]: peripheral Info:" + << "[address of peripheral: " << perifAddr << "]" + << "[address of pc: " << pcAddr << "]" + << "[hash of pc and context: " << hashVal << "]" + << "[the number of value: " << no << "]" + << "\n"; + + if (m_DRDetected.find(perifAddr) == m_DRDetected.end()) { + if (isTA(perifAddr)) { + m_DRDetected.insert(perifAddr); + s2e()->getDebugStream() << "[DataInputChannelDetector]: the peripheral: " << perifAddr << " is TA DR\n"; + } + } + } + } +} + +bool DataInputChannelDetector::isTA(uint32_t perifAddr) { + auto it = m_IRQMMIOReadPerif.find(perifAddr); + if (it != m_IRQMMIOReadPerif.end()) { + return true; + } + return false; +} + +bool DataInputChannelDetector::getPeripheralExecutionState(std::string perifName, uint32_t *perifAddr, uint32_t *pcAddr, + 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 perifAddrPCAddrStr = what[1]; + std::string hashValStr = what[2]; + std::string noStr = what[3]; + + std::vector v; + splitString(perifAddrPCAddrStr, v, "_"); + *perifAddr = std::stoull(v[0].c_str(), NULL, 16); + *pcAddr = 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 diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h index 0765cc52..8ec545ae 100644 --- a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h +++ b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h @@ -94,6 +94,38 @@ class DataInputChannelDetector : public Plugin { sigc::connection m_onStateForkConn; hw::SymbolicHardware *m_symbolicHardwareConn; + std::set m_DRDetected; + std::set m_IRQMMIOReadPerif; + + /** + * Get peripheral info from execution state. + * + * @param perifEntry a entry of peripheral + * @param perifAddr address of peripheral + * @param pcAddr 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 *pcAddr, 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 address of peripheral + * @return return ture if the peripheral is DR + */ + bool isTA(uint32_t perifAddr); + public: /** * callback for peripheral MMIO read From e99e2d7cec311bf808991ced233ed0476edca777 Mon Sep 17 00:00:00 2001 From: hwk2077 Date: Thu, 6 Apr 2023 14:52:38 +0800 Subject: [PATCH 04/15] scripts: added support for debian 11 and ubuntu 22.04 --- scripts/determine_clang_binary_suffix.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) 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 From e8cc8522cbaa372797a90f407825c3a97df89683 Mon Sep 17 00:00:00 2001 From: hwk2077 Date: Fri, 7 Apr 2023 16:14:10 +0800 Subject: [PATCH 05/15] feat: TC, restructure TA better store perif info feat: improve TA identify, implement TC identify restructure: TA and TC, add TODO fo TB add debug info and erase CR SR. --- klee/lib/Core/Executor.cpp | 2 + libs2ecore/src/S2EExecutor.cpp | 4 +- .../Plugins/uEmu/DataInputChannelDetector.cpp | 212 +++++++++++++++--- .../Plugins/uEmu/DataInputChannelDetector.h | 91 ++------ 4 files changed, 208 insertions(+), 101 deletions(-) diff --git a/klee/lib/Core/Executor.cpp b/klee/lib/Core/Executor.cpp index 4a6ba453..5ce13742 100644 --- a/klee/lib/Core/Executor.cpp +++ b/klee/lib/Core/Executor.cpp @@ -1099,6 +1099,7 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { executeMemoryOperation(state, false, base, 0, ki); break; } + // TODO case Instruction::Store: { ref base = eval(ki, 1, state).value; ref value = eval(ki, 0, state).value; @@ -1790,6 +1791,7 @@ ref Executor::executeMemoryOperation(ExecutionState &state, const ObjectSt return NULL; } +// TODO void Executor::executeMemoryOperation(ExecutionState &state, bool isWrite, ref address, ref value /* undef if read */, KInstruction *target /* undef if write */) { Expr::Width type = (isWrite ? value->getWidth() : kmodule->getWidthForLLVMType(target->inst->getType())); diff --git a/libs2ecore/src/S2EExecutor.cpp b/libs2ecore/src/S2EExecutor.cpp index 7be40c44..097f7984 100644 --- a/libs2ecore/src/S2EExecutor.cpp +++ b/libs2ecore/src/S2EExecutor.cpp @@ -1081,6 +1081,7 @@ void S2EExecutor::prepareFunctionExecution(S2EExecutionState *state, llvm::Funct } } +// TODO inline bool S2EExecutor::executeInstructions(S2EExecutionState *state, unsigned callerStackSize) { try { while (state->stack.size() != callerStackSize) { @@ -1096,6 +1097,7 @@ inline bool S2EExecutor::executeInstructions(S2EExecutionState *state, unsigned } state->stepInstruction(); + // TODO executeInstruction(*state, ki); updateStates(state); @@ -1367,7 +1369,7 @@ void S2EExecutor::cleanupTranslationBlock(S2EExecutionState *state) { state->prevPC = 0; state->pc = m_dummyMain->getInstructions(); } - +// TODO klee::ref S2EExecutor::executeFunction(S2EExecutionState *state, llvm::Function *function, const std::vector> &args) { assert(!state->isRunningConcrete()); diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp index 37a050e4..5cc0b197 100644 --- a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp +++ b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp @@ -22,6 +22,9 @@ S2E_DEFINE_PLUGIN(DataInputChannelDetector, "DataInputChannelDetector S2E plugin "SymbolicHardware"); class DataInputChannelDetectorState : public PluginState { +private: + ReadPerifMap m_readPerifSizeMap; + public: DataInputChannelDetectorState() { } @@ -35,6 +38,24 @@ class DataInputChannelDetectorState : public PluginState { 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() { @@ -48,60 +69,185 @@ void DataInputChannelDetector::initialize() { } void DataInputChannelDetector::onMMIORead(S2EExecutionState *state, SymbolicHardwareAccessType type, uint32_t perifAddr, - unsigned perifSize, uint32_t *symbVal, bool *perifFlag, - std::stringstream *ss) { - // DECLARE_PLUGINSTATE(DataInputChannelDetectorState, state); - s2e()->getDebugStream() << "[DataInputChannelDetector]: onMMIORead" << '\n'; + 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 - s2e()->getDebugStream() << "[DataInputChannelDetector]: MMIO read in external IRQ: " << perifAddr << '\n'; - m_IRQMMIOReadPerif.insert(perifAddr); + s2e()->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) { + s2e()->getDebugStream() << "[DataInputChannelDetector] All peripherals read in IRQ: " + << "[peripheral address: " << hexval(it.first) << "] " + << "[pc: " << hexval(it2.first) << "] " + << "\n"; + for (const auto &it3 : it2.second) { + s2e()->getDebugStream() << "[data size: " << it3 << "] " + << "\n"; + } + } } } void DataInputChannelDetector::onStateFork(S2EExecutionState *state, const std::vector &newStates, const std::vector> &newConditions) { + s2e()->getDebugStream() << "[DataInputChannelDetector] onStateFork" << '\n'; + // DECLARE_PLUGINSTATE(DataInputChannelDetectorState, state); - s2e()->getDebugStream() << "[DataInputChannelDetector]: onStateFork" << '\n'; + // each new states for (int k = newStates.size() - 1; k >= 0; --k) { - // DECLARE_PLUGINSTATE(DataInputChannelDetectorState, newStates[k]); - ArrayVec results; - findSymbolicObjects(newConditions[0], results); - for (int i = results.size() - 1; i >= 0; --i) { + 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 pcAddr; + uint32_t pc; uint64_t hashVal; uint64_t no; - auto &arr = results[i]; - std::vector data; - getPeripheralExecutionState(arr->getName(), &perifAddr, &pcAddr, &hashVal, &no); - s2e()->getDebugStream() << "[DataInputChannelDetector]: peripheral Info:" - << "[address of peripheral: " << perifAddr << "]" - << "[address of pc: " << pcAddr << "]" - << "[hash of pc and context: " << hashVal << "]" - << "[the number of value: " << 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); + + s2e()->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"; - if (m_DRDetected.find(perifAddr) == m_DRDetected.end()) { - if (isTA(perifAddr)) { - m_DRDetected.insert(perifAddr); - s2e()->getDebugStream() << "[DataInputChannelDetector]: the peripheral: " << perifAddr << " is TA DR\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); + s2e()->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(state, perifAddr, pc); } } } + identifyTC(); +} + +void DataInputChannelDetector::identifyTA(S2EExecutionState *state, const uint32_t &perifAddr, const uint32_t &pc) { + s2e()->getDebugStream() << "[DataInputChannelDetector] identifyTA " + << "[peripheral address: " << hexval(perifAddr) << "] " + << "[pc: " << hexval(pc) << "] " << '\n'; + const auto &foundPossIRQCRSR = m_IRQMMIOReadPossCRSR.find(perifAddr); + if (foundPossIRQCRSR != m_IRQMMIOReadPossCRSR.end()) { + s2e()->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()) { + s2e()->getDebugStream() << "return, already identified as DR: " << hexval(perifAddr) << '\n'; + return; + } + m_DRDetected[perifAddr][pc] = m_IRQMMIOReadPerifPCToPerifSizeSetMap[perifAddr][pc]; + s2e()->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()) { + s2e()->getDebugStream() << "return, unable to find a overlap: " << hexval(perifAddr) << '\n'; + return; + } + m_DRDetected[perifAddr][pc] = m_IRQMMIOReadPerifPCToPerifSizeSetMap[perifAddr][pc]; + s2e()->getDebugStream() << "Identified by TA: " + << "[peripheral address: " << hexval(perifAddr) << "] " + << "[pc: " << hexval(pc) << "] " + << "\n"; } -bool DataInputChannelDetector::isTA(uint32_t perifAddr) { - auto it = m_IRQMMIOReadPerif.find(perifAddr); - if (it != m_IRQMMIOReadPerif.end()) { - return true; +void DataInputChannelDetector::identifyTC() { + s2e()->getDebugStream() << "[DataInputChannelDetector] identifyTC" << '\n'; + for (const auto &it : m_IRQMMIOReadPerifPCToValSetMap) { + const auto &foundPossIRQCRSR = m_IRQMMIOReadPossCRSR.find(it.first); + if (foundPossIRQCRSR != m_IRQMMIOReadPossCRSR.end()) { + s2e()->getDebugStream() << "continue, peripheral is a possible CR/SR in IRQ: " << hexval(it.first) << '\n'; + continue; + } + s2e()->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()) { + s2e()->getDebugStream() << "continue, already identified as DR: " << hexval(it.first) << '\n'; + continue ; + } + } + + s2e()->getDebugStream() << "[pc: " << hexval(it2.first) << "] " + << "[same pc count: " << it2.second.size() << "] " + << "\n"; + if (it2.second.size() < 2) { + continue; + } + for (const auto &it3 : it2.second) { + s2e()->getDebugStream() << "[value: " << hexval(it3) << "] "; + } + s2e()->getDebugStream() << "\n"; + if (it2.second.size() > 3) { + m_DRDetected[it.first][it2.first] = m_IRQMMIOReadPerifPCToPerifSizeSetMap[it.first][it2.first]; + s2e()->getDebugStream() << "Identified by TC: " + << "[peripheral address: " << hexval(it.first) << "] " + << "\n"; + } + } } - return false; } -bool DataInputChannelDetector::getPeripheralExecutionState(std::string perifName, uint32_t *perifAddr, uint32_t *pcAddr, +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)) { @@ -117,14 +263,14 @@ bool DataInputChannelDetector::getPeripheralExecutionState(std::string perifName return false; } - std::string perifAddrPCAddrStr = what[1]; + std::string perifAddrPCStr = what[1]; std::string hashValStr = what[2]; std::string noStr = what[3]; std::vector v; - splitString(perifAddrPCAddrStr, v, "_"); + splitString(perifAddrPCStr, v, "_"); *perifAddr = std::stoull(v[0].c_str(), NULL, 16); - *pcAddr = std::stoull(v[1].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); diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h index 8ec545ae..fe7491a8 100644 --- a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h +++ b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h @@ -15,71 +15,18 @@ namespace s2e { namespace plugins { -enum DataRegisterType { TA, TB, TC, TD }; -enum PeripheralRegisterType { TIRQS, TIRQC, T0, T1, PT1, T2, T3 }; -enum KBUpdateReason { Valid, Invlid }; - -// For General Peripheral in KB: T0~T3 using PerifAddr = uint32_t; -using PCAddr = uint32_t; +using PC = uint32_t; using PCCtxHash = uint64_t; using PerifVal = uint32_t; - -// For IRQ Peripheral in KB: TIRQS TIRQC -using IRQNo = uint32_t; -using CRAddr = uint32_t; -using CRVal = uint32_t; - -// For DR in KB using PerifSize = uint32_t; -// util -using PerifPCPair = std::pair; - -using ValNo = uint64_t; -using NoValPair = std::pair; -using NoValMap = std::map; - -using PCCtxHashPerifValMap = std::map; -using PCCtxHashNoValPairMap = std::map; - -using IRQNoPerifAddrPair = std::pair; -using IRQNoPerifPCTuple = std::tuple; -using IRQCRMap = std::map>>; -using IRQSRMap = std::map; - -using T2PerifTuple = std::tuple; - using ReadPerifMap = std::map>; -using ReadPerifTuple = std::pair>; - -using ConcreteArray = std::vector; - using PerifAddrPerifSizeMap = std::map; -using PerifAddrPerifValMap = std::map; -using PerifAddrForkCntMap = std::map; -using ForkStateStack = std::vector>; - -// For Flag -using PerifFlag = uint32_t; -using PerifAddrToPerifFlagMap = std::map; -using TIRQPerifToPerifFlagMap = std::map; -using TIRQSPerifToPerifFlagMap = std::map; - -// peripheral Map -using PerifMap = std::map; -using T0PerifMap = std::map>>; -using T1PerifMap = std::map; -using T1BPerifMap = std::map>; -using T1BNPerifMap = std::map>; -using T2PerifMap = std::map; -using T3PerifMap = std::map>; -using TIRQCPerifMap = std::map; -using TIRQSPerifMap = std::map>; - -// KB -using AllKnowledgeBaseMap = std::map; -using AllKnowledgeBaseNoMap = std::map; + +using PerifAddrToPCSetMap = std::map>; +using PerifAddrPCToPerifSizeSetMap = std::map>>; +using PerifAddrPCToValSetMap = std::map>>; class DataInputChannelDetector : public Plugin { S2E_PLUGIN @@ -94,20 +41,23 @@ class DataInputChannelDetector : public Plugin { sigc::connection m_onStateForkConn; hw::SymbolicHardware *m_symbolicHardwareConn; - std::set m_DRDetected; - std::set m_IRQMMIOReadPerif; + 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 pcAddr address of pc + * @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 *pcAddr, uint64_t *hashVal, + bool getPeripheralExecutionState(std::string perifEntry, uint32_t *perifAddr, uint32_t *pc, uint64_t *hashVal, uint64_t *no); /** @@ -121,10 +71,17 @@ class DataInputChannelDetector : public Plugin { /** * identify TA DR. * - * @param perifAddr address of peripheral - * @return return ture if the peripheral is DR + * @param state state to identify whether IRQ is triggered + * @param perifAddr peripheral address + * @param pc pc address + */ + void identifyTA(S2EExecutionState *state, const uint32_t &perifAddr, const uint32_t &pc); + + /** + * identify TC DR. + * */ - bool isTA(uint32_t perifAddr); + void identifyTC(); public: /** @@ -133,12 +90,12 @@ class DataInputChannelDetector : public Plugin { * @param type * @param perifAddr address of peripheral * @param perifSize data size of peripheral - * @param symbVal symbolic value + * @param val value * @param perifFlag flag of peripheral * @param ss */ void onMMIORead(S2EExecutionState *state, SymbolicHardwareAccessType type, uint32_t perifAddr, unsigned perifSize, - uint32_t *symbVal, bool *perifFlag, std::stringstream *ss); + uint32_t *val, bool *perifFlag, std::stringstream *ss); /** * callback when state fork From 650f57fed07c5d86528589b795907c5c3d64f76d Mon Sep 17 00:00:00 2001 From: hwk2077 Date: Thu, 13 Apr 2023 22:48:02 +0800 Subject: [PATCH 06/15] feat: identify TB DR --- klee/lib/Core/Executor.cpp | 2 - libs2ecore/include/s2e/CorePlugin.h | 10 ++ libs2ecore/src/FunctionHandlers.cpp | 8 +- libs2ecore/src/S2EExecutor.cpp | 4 +- .../Plugins/uEmu/DataInputChannelDetector.cpp | 105 +++++++++++++++++- .../Plugins/uEmu/DataInputChannelDetector.h | 27 ++++- 6 files changed, 142 insertions(+), 14 deletions(-) diff --git a/klee/lib/Core/Executor.cpp b/klee/lib/Core/Executor.cpp index 5ce13742..4a6ba453 100644 --- a/klee/lib/Core/Executor.cpp +++ b/klee/lib/Core/Executor.cpp @@ -1099,7 +1099,6 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) { executeMemoryOperation(state, false, base, 0, ki); break; } - // TODO case Instruction::Store: { ref base = eval(ki, 1, state).value; ref value = eval(ki, 0, state).value; @@ -1791,7 +1790,6 @@ ref Executor::executeMemoryOperation(ExecutionState &state, const ObjectSt return NULL; } -// TODO void Executor::executeMemoryOperation(ExecutionState &state, bool isWrite, ref address, ref value /* undef if read */, KInstruction *target /* undef if write */) { Expr::Width type = (isWrite ? value->getWidth() : kmodule->getWidthForLLVMType(target->inst->getType())); 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/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 097f7984..7be40c44 100644 --- a/libs2ecore/src/S2EExecutor.cpp +++ b/libs2ecore/src/S2EExecutor.cpp @@ -1081,7 +1081,6 @@ void S2EExecutor::prepareFunctionExecution(S2EExecutionState *state, llvm::Funct } } -// TODO inline bool S2EExecutor::executeInstructions(S2EExecutionState *state, unsigned callerStackSize) { try { while (state->stack.size() != callerStackSize) { @@ -1097,7 +1096,6 @@ inline bool S2EExecutor::executeInstructions(S2EExecutionState *state, unsigned } state->stepInstruction(); - // TODO executeInstruction(*state, ki); updateStates(state); @@ -1369,7 +1367,7 @@ void S2EExecutor::cleanupTranslationBlock(S2EExecutionState *state) { state->prevPC = 0; state->pc = m_dummyMain->getInstructions(); } -// TODO + klee::ref S2EExecutor::executeFunction(S2EExecutionState *state, llvm::Function *function, const std::vector> &args) { assert(!state->isRunningConcrete()); diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp index 5cc0b197..24644f72 100644 --- a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp +++ b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp @@ -66,6 +66,10 @@ void DataInputChannelDetector::initialize() { 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, @@ -99,6 +103,62 @@ void DataInputChannelDetector::onMMIORead(S2EExecutionState *state, SymbolicHard } } +void DataInputChannelDetector::onSymbolicDataAccessConcreteMemory(S2EExecutionState *state, uint64_t concreteAddr, + klee::ref symbVal, bool isWrite) { + s2e()->getDebugStream() << "[DataInputChannelDetector] onSymbolicDataAccessConcreteMemory" + << "[concrete address: " << hexval(concreteAddr) << "] " + << "[symbolic value: " << symbVal << "] " + << "\n"; + + DECLARE_PLUGINSTATE(DataInputChannelDetectorState, state); + ReadPerifMap curStateReadPerifSizeMap = plgState->getReadPerifSizeMap(); + ArrayVec results; + findSymbolicObjects(symbVal, results); + s2e()->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); + + s2e()->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) { s2e()->getDebugStream() << "[DataInputChannelDetector] onStateFork" << '\n'; @@ -163,14 +223,14 @@ void DataInputChannelDetector::onStateFork(S2EExecutionState *state, const std:: if (val != 0) { m_IRQMMIOReadPerifPCToValSetMap[perifAddr][pc].insert(val); } - identifyTA(state, perifAddr, pc); + identifyTA(perifAddr, pc); } } } - identifyTC(); + identifyTC(); } -void DataInputChannelDetector::identifyTA(S2EExecutionState *state, const uint32_t &perifAddr, const uint32_t &pc) { +void DataInputChannelDetector::identifyTA(const uint32_t &perifAddr, const uint32_t &pc) { s2e()->getDebugStream() << "[DataInputChannelDetector] identifyTA " << "[peripheral address: " << hexval(perifAddr) << "] " << "[pc: " << hexval(pc) << "] " << '\n'; @@ -207,6 +267,43 @@ void DataInputChannelDetector::identifyTA(S2EExecutionState *state, const uint32 << "\n"; } +void DataInputChannelDetector::identifyTB(const uint32_t &perifAddr, const uint32_t &pc) { + s2e()->getDebugStream() << "[DataInputChannelDetector] identifyTB " + << "[peripheral address: " << hexval(perifAddr) << "] " + << "[pc: " << hexval(pc) << "] " << '\n'; + const auto &foundPossIRQCRSR = m_IRQMMIOReadPossCRSR.find(perifAddr); + if (foundPossIRQCRSR != m_IRQMMIOReadPossCRSR.end()) { + s2e()->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()) { + s2e()->getDebugStream() << "return, already identified as DR: " << hexval(perifAddr) << '\n'; + return; + } + m_DRDetected[perifAddr][pc] = m_IRQMMIOReadPerifPCToPerifSizeSetMap[perifAddr][pc]; + s2e()->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()) { + s2e()->getDebugStream() << "return, unable to find a overlap: " << hexval(perifAddr) << '\n'; + return; + } + m_DRDetected[perifAddr][pc] = m_IRQMMIOReadPerifPCToPerifSizeSetMap[perifAddr][pc]; + s2e()->getDebugStream() << "Identified by TB: " + << "[peripheral address: " << hexval(perifAddr) << "] " + << "[pc: " << hexval(pc) << "] " + << "\n"; +} + void DataInputChannelDetector::identifyTC() { s2e()->getDebugStream() << "[DataInputChannelDetector] identifyTC" << '\n'; for (const auto &it : m_IRQMMIOReadPerifPCToValSetMap) { @@ -223,7 +320,7 @@ void DataInputChannelDetector::identifyTC() { const auto &foundSamePC = m_DRDetected[it.first].find(it2.first); if (foundSamePC != m_DRDetected[it.first].end()) { s2e()->getDebugStream() << "continue, already identified as DR: " << hexval(it.first) << '\n'; - continue ; + continue; } } diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h index fe7491a8..83c2f227 100644 --- a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h +++ b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.h @@ -39,6 +39,8 @@ class DataInputChannelDetector : public Plugin { private: sigc::connection m_onStateForkConn; + sigc::connection m_onSymbolicDataAccessConcreteMemoryConn; + sigc::connection m_onBeforeSymbolicDataMemoryAccessConn; hw::SymbolicHardware *m_symbolicHardwareConn; PerifAddrPCToPerifSizeSetMap m_DRDetected; @@ -71,11 +73,18 @@ class DataInputChannelDetector : public Plugin { /** * identify TA DR. * - * @param state state to identify whether IRQ is triggered * @param perifAddr peripheral address * @param pc pc address */ - void identifyTA(S2EExecutionState *state, const uint32_t &perifAddr, const uint32_t &pc); + 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. @@ -97,6 +106,20 @@ class DataInputChannelDetector : public Plugin { 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 From 6a120118b6a25802290ce1f04bda03c6a95afd90 Mon Sep 17 00:00:00 2001 From: hwk2077 Date: Mon, 17 Apr 2023 19:37:24 +0800 Subject: [PATCH 07/15] fix: debugstream --- .../Plugins/uEmu/DataInputChannelDetector.cpp | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp index 24644f72..f22522aa 100644 --- a/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp +++ b/libs2eplugins/src/s2e/Plugins/uEmu/DataInputChannelDetector.cpp @@ -82,7 +82,7 @@ void DataInputChannelDetector::onMMIORead(S2EExecutionState *state, SymbolicHard if (state->regs()->getInterruptFlag() && state->regs()->getExceptionIndex() > 15) { // external irq handle - s2e()->getDebugStream() << "[DataInputChannelDetector] MMIO read in external IRQ: " + getDebugStream() << "[DataInputChannelDetector] MMIO read in external IRQ: " << "[peripheral address: " << hexval(perifAddr) << "] " << "[pc: " << hexval(pc) << "] " << "[value: " << hexval(*val) << "] " @@ -91,12 +91,12 @@ void DataInputChannelDetector::onMMIORead(S2EExecutionState *state, SymbolicHard } for (const auto &it : m_IRQMMIOReadPerifPCToPerifSizeSetMap) { for (const auto &it2 : it.second) { - s2e()->getDebugStream() << "[DataInputChannelDetector] All peripherals read in IRQ: " + getDebugStream() << "[DataInputChannelDetector] All peripherals read in IRQ: " << "[peripheral address: " << hexval(it.first) << "] " << "[pc: " << hexval(it2.first) << "] " << "\n"; for (const auto &it3 : it2.second) { - s2e()->getDebugStream() << "[data size: " << it3 << "] " + getDebugStream() << "[data size: " << it3 << "] " << "\n"; } } @@ -105,7 +105,7 @@ void DataInputChannelDetector::onMMIORead(S2EExecutionState *state, SymbolicHard void DataInputChannelDetector::onSymbolicDataAccessConcreteMemory(S2EExecutionState *state, uint64_t concreteAddr, klee::ref symbVal, bool isWrite) { - s2e()->getDebugStream() << "[DataInputChannelDetector] onSymbolicDataAccessConcreteMemory" + getDebugStream() << "[DataInputChannelDetector] onSymbolicDataAccessConcreteMemory" << "[concrete address: " << hexval(concreteAddr) << "] " << "[symbolic value: " << symbVal << "] " << "\n"; @@ -114,7 +114,7 @@ void DataInputChannelDetector::onSymbolicDataAccessConcreteMemory(S2EExecutionSt ReadPerifMap curStateReadPerifSizeMap = plgState->getReadPerifSizeMap(); ArrayVec results; findSymbolicObjects(symbVal, results); - s2e()->getDebugStream() << "[size of results: " << results.size() << "] " + getDebugStream() << "[size of results: " << results.size() << "] " << "\n"; for (int i = results.size() - 1; i >= 0; --i) { uint32_t perifAddr; @@ -143,7 +143,7 @@ void DataInputChannelDetector::onSymbolicDataAccessConcreteMemory(S2EExecutionSt uint64_t LSB = ((uint64_t) 1 << (curStateReadPerifSizeMap[perifAddr].first * 8)); uint32_t val = condConcreteVal & (LSB - 1); - s2e()->getDebugStream() << "solve symbolic value: " + getDebugStream() << "solve symbolic value: " << "[peripheral address: " << hexval(perifAddr) << "]" << "[pc: " << hexval(pc) << "]" << "[hash of pc and context: " << hexval(hashVal) << "]" @@ -161,7 +161,7 @@ void DataInputChannelDetector::onBeforeSymbolicDataMemoryAccess(S2EExecutionStat void DataInputChannelDetector::onStateFork(S2EExecutionState *state, const std::vector &newStates, const std::vector> &newConditions) { - s2e()->getDebugStream() << "[DataInputChannelDetector] onStateFork" << '\n'; + getDebugStream() << "[DataInputChannelDetector] onStateFork" << '\n'; // DECLARE_PLUGINSTATE(DataInputChannelDetectorState, state); @@ -200,7 +200,7 @@ void DataInputChannelDetector::onStateFork(S2EExecutionState *state, const std:: uint64_t LSB = ((uint64_t) 1 << (curStateReadPerifSizeMap[perifAddr].first * 8)); uint32_t val = condConcreteVal & (LSB - 1); - s2e()->getDebugStream() << "condition register Info: " + getDebugStream() << "condition register Info: " << "[peripheral address: " << hexval(perifAddr) << "]" << "[pc: " << hexval(pc) << "]" << "[hash of pc and context: " << hexval(hashVal) << "]" @@ -214,7 +214,7 @@ void DataInputChannelDetector::onStateFork(S2EExecutionState *state, const std:: const auto &foundPossCRSR = m_IRQMMIOReadPerifPCToPerifSizeSetMap.find(perifAddr); if (foundPossCRSR != m_IRQMMIOReadPerifPCToPerifSizeSetMap.end()) { m_IRQMMIOReadPossCRSR[perifAddr].insert(pc); - s2e()->getDebugStream() << "found a possible CR/SR peripheral in IRQ: " + getDebugStream() << "found a possible CR/SR peripheral in IRQ: " << "[peripheral address: " << hexval(perifAddr) << "] " << "[pc: " << hexval(pc) << "] " << "\n"; @@ -231,12 +231,12 @@ void DataInputChannelDetector::onStateFork(S2EExecutionState *state, const std:: } void DataInputChannelDetector::identifyTA(const uint32_t &perifAddr, const uint32_t &pc) { - s2e()->getDebugStream() << "[DataInputChannelDetector] identifyTA " + getDebugStream() << "[DataInputChannelDetector] identifyTA " << "[peripheral address: " << hexval(perifAddr) << "] " << "[pc: " << hexval(pc) << "] " << '\n'; const auto &foundPossIRQCRSR = m_IRQMMIOReadPossCRSR.find(perifAddr); if (foundPossIRQCRSR != m_IRQMMIOReadPossCRSR.end()) { - s2e()->getDebugStream() << "return, peripheral is a possible CR/SR in IRQ: " << hexval(perifAddr) << '\n'; + getDebugStream() << "return, peripheral is a possible CR/SR in IRQ: " << hexval(perifAddr) << '\n'; return; } @@ -244,11 +244,11 @@ void DataInputChannelDetector::identifyTA(const uint32_t &perifAddr, const uint3 if (foundSamePerif != m_DRDetected.end()) { const auto &foundSamePC = m_DRDetected[perifAddr].find(pc); if (foundSamePC != m_DRDetected[perifAddr].end()) { - s2e()->getDebugStream() << "return, already identified as DR: " << hexval(perifAddr) << '\n'; + getDebugStream() << "return, already identified as DR: " << hexval(perifAddr) << '\n'; return; } m_DRDetected[perifAddr][pc] = m_IRQMMIOReadPerifPCToPerifSizeSetMap[perifAddr][pc]; - s2e()->getDebugStream() << "Identified by TA: " + getDebugStream() << "Identified by TA: " << "[peripheral address: " << hexval(perifAddr) << "] " << "[pc: " << hexval(pc) << "] " << "\n"; @@ -257,23 +257,23 @@ void DataInputChannelDetector::identifyTA(const uint32_t &perifAddr, const uint3 const auto &foundOverlap = m_IRQMMIOReadPerifPCToPerifSizeSetMap.find(perifAddr); if (foundOverlap == m_IRQMMIOReadPerifPCToPerifSizeSetMap.end()) { - s2e()->getDebugStream() << "return, unable to find a overlap: " << hexval(perifAddr) << '\n'; + getDebugStream() << "return, unable to find a overlap: " << hexval(perifAddr) << '\n'; return; } m_DRDetected[perifAddr][pc] = m_IRQMMIOReadPerifPCToPerifSizeSetMap[perifAddr][pc]; - s2e()->getDebugStream() << "Identified by TA: " + getDebugStream() << "Identified by TA: " << "[peripheral address: " << hexval(perifAddr) << "] " << "[pc: " << hexval(pc) << "] " << "\n"; } void DataInputChannelDetector::identifyTB(const uint32_t &perifAddr, const uint32_t &pc) { - s2e()->getDebugStream() << "[DataInputChannelDetector] identifyTB " + getDebugStream() << "[DataInputChannelDetector] identifyTB " << "[peripheral address: " << hexval(perifAddr) << "] " << "[pc: " << hexval(pc) << "] " << '\n'; const auto &foundPossIRQCRSR = m_IRQMMIOReadPossCRSR.find(perifAddr); if (foundPossIRQCRSR != m_IRQMMIOReadPossCRSR.end()) { - s2e()->getDebugStream() << "return, peripheral is a possible CR/SR in IRQ: " << hexval(perifAddr) << '\n'; + getDebugStream() << "return, peripheral is a possible CR/SR in IRQ: " << hexval(perifAddr) << '\n'; return; } @@ -281,11 +281,11 @@ void DataInputChannelDetector::identifyTB(const uint32_t &perifAddr, const uint3 if (foundSamePerif != m_DRDetected.end()) { const auto &foundSamePC = m_DRDetected[perifAddr].find(pc); if (foundSamePC != m_DRDetected[perifAddr].end()) { - s2e()->getDebugStream() << "return, already identified as DR: " << hexval(perifAddr) << '\n'; + getDebugStream() << "return, already identified as DR: " << hexval(perifAddr) << '\n'; return; } m_DRDetected[perifAddr][pc] = m_IRQMMIOReadPerifPCToPerifSizeSetMap[perifAddr][pc]; - s2e()->getDebugStream() << "Identified by TB: " + getDebugStream() << "Identified by TB: " << "[peripheral address: " << hexval(perifAddr) << "] " << "[pc: " << hexval(pc) << "] " << "\n"; @@ -294,49 +294,49 @@ void DataInputChannelDetector::identifyTB(const uint32_t &perifAddr, const uint3 const auto &foundOverlap = m_IRQMMIOReadPerifPCToPerifSizeSetMap.find(perifAddr); if (foundOverlap == m_IRQMMIOReadPerifPCToPerifSizeSetMap.end()) { - s2e()->getDebugStream() << "return, unable to find a overlap: " << hexval(perifAddr) << '\n'; + getDebugStream() << "return, unable to find a overlap: " << hexval(perifAddr) << '\n'; return; } m_DRDetected[perifAddr][pc] = m_IRQMMIOReadPerifPCToPerifSizeSetMap[perifAddr][pc]; - s2e()->getDebugStream() << "Identified by TB: " + getDebugStream() << "Identified by TB: " << "[peripheral address: " << hexval(perifAddr) << "] " << "[pc: " << hexval(pc) << "] " << "\n"; } void DataInputChannelDetector::identifyTC() { - s2e()->getDebugStream() << "[DataInputChannelDetector] identifyTC" << '\n'; + getDebugStream() << "[DataInputChannelDetector] identifyTC" << '\n'; for (const auto &it : m_IRQMMIOReadPerifPCToValSetMap) { const auto &foundPossIRQCRSR = m_IRQMMIOReadPossCRSR.find(it.first); if (foundPossIRQCRSR != m_IRQMMIOReadPossCRSR.end()) { - s2e()->getDebugStream() << "continue, peripheral is a possible CR/SR in IRQ: " << hexval(it.first) << '\n'; + getDebugStream() << "continue, peripheral is a possible CR/SR in IRQ: " << hexval(it.first) << '\n'; continue; } - s2e()->getDebugStream() << "[peripheral address: " << hexval(it.first) << "] " + 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()) { - s2e()->getDebugStream() << "continue, already identified as DR: " << hexval(it.first) << '\n'; + getDebugStream() << "continue, already identified as DR: " << hexval(it.first) << '\n'; continue; } } - s2e()->getDebugStream() << "[pc: " << hexval(it2.first) << "] " + getDebugStream() << "[pc: " << hexval(it2.first) << "] " << "[same pc count: " << it2.second.size() << "] " << "\n"; if (it2.second.size() < 2) { continue; } for (const auto &it3 : it2.second) { - s2e()->getDebugStream() << "[value: " << hexval(it3) << "] "; + getDebugStream() << "[value: " << hexval(it3) << "] "; } - s2e()->getDebugStream() << "\n"; + getDebugStream() << "\n"; if (it2.second.size() > 3) { m_DRDetected[it.first][it2.first] = m_IRQMMIOReadPerifPCToPerifSizeSetMap[it.first][it2.first]; - s2e()->getDebugStream() << "Identified by TC: " + getDebugStream() << "Identified by TC: " << "[peripheral address: " << hexval(it.first) << "] " << "\n"; } From 8fe5fe98612052337715a07a372da3976b228657 Mon Sep 17 00:00:00 2001 From: hwk2077 Date: Sat, 15 Apr 2023 19:57:50 +0800 Subject: [PATCH 08/15] init plugin: MultiPathSearcher --- libs2eplugins/src/CMakeLists.txt | 1 + .../Plugins/Searchers/ValidPathSearcher.cpp | 117 ++++++++++++++++++ .../s2e/Plugins/Searchers/ValidPathSearcher.h | 89 +++++++++++++ 3 files changed, 207 insertions(+) create mode 100644 libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp create mode 100644 libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h diff --git a/libs2eplugins/src/CMakeLists.txt b/libs2eplugins/src/CMakeLists.txt index 11faa988..991bc952 100644 --- a/libs2eplugins/src/CMakeLists.txt +++ b/libs2eplugins/src/CMakeLists.txt @@ -223,6 +223,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..5ab67c41 --- /dev/null +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp @@ -0,0 +1,117 @@ +/// +/// 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 MultiPathSearcherState : public PluginState { +private: +public: + MultiPathSearcherState() { + } + virtual ~MultiPathSearcherState() { + } + + static PluginState *factory(Plugin *, S2EExecutionState *) { + return new MultiPathSearcherState(); + } + + MultiPathSearcherState *clone() const { + return new MultiPathSearcherState(*this); + } +}; + +void ValidPathSearcher::initialize() { + m_onStateForkConn = + s2e()->getCorePlugin()->onStateFork.connect(sigc::mem_fun(*this, &ValidPathSearcher::onStateFork)); + + onARMFunctionConn = s2e()->getPlugin(); + onARMFunctionConn->onARMFunctionCallEvent.connect(sigc::mem_fun(*this, &ValidPathSearcher::onARMFunctionCall)); + onARMFunctionConn->onARMFunctionReturnEvent.connect(sigc::mem_fun(*this, &ValidPathSearcher::onARMFunctionReturn)); +} + +void ValidPathSearcher::onStateFork(S2EExecutionState *state, const std::vector &newStates, + const std::vector> &newConditions) { + s2e()->getDebugStream() << "[ValidPathSearcher] onStateFork" << '\n'; + + uint32_t pc = state->regs()->getPc(); + S2EExecutionState *first, *second; + first = newStates[0]; + second = newStates[1]; + s2e()->getDebugStream() << "fork state condition PC: " << hexval(pc) << "\n"; + + m_forkStates[m_pcCaller][pc].push_back(first); + m_forkStates[m_pcCaller][pc].push_back(second); + m_forkStatesBak[m_pcCaller][pc].push_back(first); + m_forkStatesBak[m_pcCaller][pc].push_back(second); +} + +void ValidPathSearcher::onARMFunctionCall(S2EExecutionState *state, uint32_t pcCaller, uint64_t pcCtxHashVal) { + s2e()->getDebugStream() << "[ValidPathSearcher] onARMFunctionCall" + << "\n"; + + m_pcCaller = pcCaller; + s2e()->getDebugStream() << "[record call pc: " << hexval(pcCaller) << "] " + << "[pc and context hash: " << hexval(pcCtxHashVal) << "] " + << "\n"; +} + +void ValidPathSearcher::onARMFunctionReturn(S2EExecutionState *state, uint32_t pcReturn) { + s2e()->getDebugStream() << "[ValidPathSearcher] onARMFunctionReturn" + << "\n"; + m_curState = state; + m_pcReturn = pcReturn; + s2e()->getDebugStream() << "[state ID: " << hexval(m_curState->getID()) << "] " + << "[pc: " << hexval(pcReturn) << "] " + << "\n"; +} + +klee::ExecutionState &ValidPathSearcher::DFS(S2EExecutionState *state, uint32_t condPC) { + s2e()->getDebugStream() << "[ValidPathSearcher] DFS" + << "\n"; + auto it = m_forkStatesBak[m_pcCaller].begin(); + for (; it != m_forkStatesBak[m_pcCaller].end(); it++) { + S2EExecutionState *f, *s; + uint32_t parentPC, pc1, pc2; + f = it->second[0]; + s = it->second[1]; + parentPC = it->first; + pc1 = f->regs()->getPc(); + pc2 = s->regs()->getPc(); + + std::vector tmp = m_forkStates[m_pcCaller][parentPC]; + if (tim.size() != 2) { + condPC = parentPC; + } else { + tmp.clear(); + if (pc1 == condPC) { + m_curState = s; + } else if (pc2 == condPC) { + m_curState = f; + } else { + exit(1); + } + s2e()->getDebugStream() << "[select state: " << hexval(m_curState->getID()) << "] " + << "[selected state's PC: " << hexval(m_curState->regs()->getPc()) << "] " + << "\n"; + return *m_curState; + } + } + return *state; +} + +} // 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..31d9bb7e --- /dev/null +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h @@ -0,0 +1,89 @@ +/// +/// 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 + +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 Searchers = std::map; + +class ValidPathSearcher : public Plugin, public klee::Searcher { + S2E_PLUGIN + +public: + ValidPathSearcher(S2E *s2e) : Plugin(s2e) { + } + + void initialize(); + +private: + sigc::connection m_onStateForkConn; + ARMFunctionMonitor *onARMFunctionConn; + + Searchers m_searchers; + klee::Searcher *m_currentSearcher; + + uint32_t m_pcCaller; + uint32_t m_pcReturn; + S2EExecutionState *m_curState; + std::map>> m_forkStates; + std::map>> m_forkStatesBak; + +public: + /** + * callback when state fork + * @param state + * @param newStates + * @param newConditions + */ + void onStateFork(S2EExecutionState *state, const std::vector &newStates, + const std::vector> &newConditions); + /** + * callback when function call. + * + * @param state s2e state + * @param pcCaller pc of caller + * @param pcCtxHashVal pc and context hash value + */ + void onARMFunctionCall(S2EExecutionState *state, uint32_t pcCaller, uint64_t pcCtxHashVal); + + /** + * callback when function return. + * + * @param state s2e state + * @param pcReturn pc of return + */ + void onARMFunctionReturn(S2EExecutionState *state, uint32_t pcReturn); + + /** + * find the state which forked the child state with the condition pc. + * + * @param state s2e state + * @param condPC condition pc from Fork. + * @return + */ + klee::ExecutionState &DFS(S2EExecutionState *state, uint32_t condPC); +}; + +} // namespace plugins +} // namespace s2e + +#endif // S2E_PLUGINS_VALIDPATHSEARCHER_H From 47f5961862dad72da21d350808817e7dc9122f47 Mon Sep 17 00:00:00 2001 From: hwk2077 Date: Sat, 6 May 2023 15:00:34 +0800 Subject: [PATCH 09/15] priority queue --- libs2eplugins/src/CMakeLists.txt | 3 +- .../Plugins/Searchers/ValidPathSearcher.cpp | 160 +++++++++++------- .../s2e/Plugins/Searchers/ValidPathSearcher.h | 67 +++++++- .../SymbolicHardware/SymbolicHardware.cpp | 3 +- .../src/s2e/Plugins/uEmu/DebugPlugin.cpp | 134 +++++++++++++++ .../src/s2e/Plugins/uEmu/DebugPlugin.h | 126 ++++++++++++++ 6 files changed, 420 insertions(+), 73 deletions(-) create mode 100644 libs2eplugins/src/s2e/Plugins/uEmu/DebugPlugin.cpp create mode 100644 libs2eplugins/src/s2e/Plugins/uEmu/DebugPlugin.h diff --git a/libs2eplugins/src/CMakeLists.txt b/libs2eplugins/src/CMakeLists.txt index 991bc952..19aecefd 100644 --- a/libs2eplugins/src/CMakeLists.txt +++ b/libs2eplugins/src/CMakeLists.txt @@ -173,6 +173,7 @@ add_library( 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 @@ -223,7 +224,7 @@ add_library( s2e/Plugins/Searchers/CUPASearcher.cpp s2e/Plugins/Searchers/SeedSearcher.cpp s2e/Plugins/Searchers/SeedScheduler.cpp - s2e/Plugins/Searchers/ValidPathSearcher.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 index 5ab67c41..899cb365 100644 --- a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp @@ -17,100 +17,132 @@ namespace plugins { S2E_DEFINE_PLUGIN(ValidPathSearcher, "ValidPathSearcher S2E plugin", "ValidPathSearcher", "ARMFunctionMonitor"); -class MultiPathSearcherState : public PluginState { -private: -public: - MultiPathSearcherState() { +bool ValidPathSearcher::insertToPriorityQueue(S2EExecutionState *state) { + if (!m_pq.empty() && m_pq.top().state->getID() >= state->getID()) { + return false; } - virtual ~MultiPathSearcherState() { - } - - static PluginState *factory(Plugin *, S2EExecutionState *) { - return new MultiPathSearcherState(); - } - - MultiPathSearcherState *clone() const { - return new MultiPathSearcherState(*this); - } -}; + m_pq.push({state, false}); + return true; +} void ValidPathSearcher::initialize() { + s2e()->getExecutor()->setSearcher(this); m_onStateForkConn = s2e()->getCorePlugin()->onStateFork.connect(sigc::mem_fun(*this, &ValidPathSearcher::onStateFork)); onARMFunctionConn = s2e()->getPlugin(); onARMFunctionConn->onARMFunctionCallEvent.connect(sigc::mem_fun(*this, &ValidPathSearcher::onARMFunctionCall)); onARMFunctionConn->onARMFunctionReturnEvent.connect(sigc::mem_fun(*this, &ValidPathSearcher::onARMFunctionReturn)); + + m_curState = nullptr; } void ValidPathSearcher::onStateFork(S2EExecutionState *state, const std::vector &newStates, const std::vector> &newConditions) { - s2e()->getDebugStream() << "[ValidPathSearcher] onStateFork" << '\n'; + getDebugStream() << "onStateFork" << '\n'; - uint32_t pc = state->regs()->getPc(); + uint32_t forkPC = state->regs()->getPc(); S2EExecutionState *first, *second; first = newStates[0]; second = newStates[1]; - s2e()->getDebugStream() << "fork state condition PC: " << hexval(pc) << "\n"; + getDebugStream() << "[forkPC: " << hexval(forkPC) << "] " + << "[stateID: " << hexval(state->getID()) << "] " + << "[new stateID: " << hexval(newStates[0]->getID()) << "] " + << "[new stateID: " << hexval(newStates[1]->getID()) << "] " + << "\n"; + + insertToPriorityQueue(newStates[0]); + insertToPriorityQueue(newStates[1]); + getDebugStream() << "[top stateID: " << hexval(m_pq.top().state->getID()) << "] " + << "\n"; + + m_forkStates[m_pcCaller][forkPC].push_back(first); + m_forkStates[m_pcCaller][forkPC].push_back(second); + m_forkStatesBak[m_pcCaller][forkPC].push_back(first); + m_forkStatesBak[m_pcCaller][forkPC].push_back(second); +} + +klee::ExecutionState &ValidPathSearcher::selectState() { + getDebugStream() << "selectState" + << "\n"; + while (!m_pq.empty()) { + if (m_pq.top().visited == true) { + m_pq.pop(); + continue; + } + m_curState = m_pq.top().state; + m_pq.pop(); + getDebugStream() << "[selected stateID: " << m_curState->getID() << "] " + << "\n"; + return *m_curState; + } + getDebugStream() << "[no option, stateID: " << m_curState->getID() << "] " + << "\n"; + return *m_curState; +} + +void ValidPathSearcher::update(klee::ExecutionState *current, const klee::StateSet &addedStates, + const klee::StateSet &removedStates) { + // getDebugStream() << "update" + // << "\n"; + for (auto it : removedStates) { + S2EExecutionState *removedState = static_cast(it); + auto it2 = m_forkStates[m_pcCaller].begin(); + for (; it2 != m_forkStates[m_pcCaller].end(); it2++) { + S2EExecutionState *f = it2->second[0]; + S2EExecutionState *s = it2->second[1]; + if (f == removedState) { + (it2->second).erase((it2->second).begin()); + } else if (s == removedState) { + (it2->second).erase((it2->second).begin() + 1); + } + } + } +} - m_forkStates[m_pcCaller][pc].push_back(first); - m_forkStates[m_pcCaller][pc].push_back(second); - m_forkStatesBak[m_pcCaller][pc].push_back(first); - m_forkStatesBak[m_pcCaller][pc].push_back(second); +bool ValidPathSearcher::empty() { + getDebugStream() << "empty" + << "\n"; + return m_pq.empty(); } void ValidPathSearcher::onARMFunctionCall(S2EExecutionState *state, uint32_t pcCaller, uint64_t pcCtxHashVal) { - s2e()->getDebugStream() << "[ValidPathSearcher] onARMFunctionCall" - << "\n"; + getDebugStream() << "onARMFunctionCall" + << "\n"; m_pcCaller = pcCaller; - s2e()->getDebugStream() << "[record call pc: " << hexval(pcCaller) << "] " - << "[pc and context hash: " << hexval(pcCtxHashVal) << "] " - << "\n"; + getDebugStream() << "[record call pc: " << hexval(pcCaller) << "] " + << "[pc and context hash: " << hexval(pcCtxHashVal) << "] " + << "\n"; } void ValidPathSearcher::onARMFunctionReturn(S2EExecutionState *state, uint32_t pcReturn) { - s2e()->getDebugStream() << "[ValidPathSearcher] onARMFunctionReturn" - << "\n"; + // for switch based on level of function. + getDebugStream() << "onARMFunctionReturn" + << "\n"; m_curState = state; m_pcReturn = pcReturn; - s2e()->getDebugStream() << "[state ID: " << hexval(m_curState->getID()) << "] " - << "[pc: " << hexval(pcReturn) << "] " - << "\n"; -} - -klee::ExecutionState &ValidPathSearcher::DFS(S2EExecutionState *state, uint32_t condPC) { - s2e()->getDebugStream() << "[ValidPathSearcher] DFS" - << "\n"; - auto it = m_forkStatesBak[m_pcCaller].begin(); - for (; it != m_forkStatesBak[m_pcCaller].end(); it++) { - S2EExecutionState *f, *s; - uint32_t parentPC, pc1, pc2; - f = it->second[0]; - s = it->second[1]; - parentPC = it->first; - pc1 = f->regs()->getPc(); - pc2 = s->regs()->getPc(); - - std::vector tmp = m_forkStates[m_pcCaller][parentPC]; - if (tim.size() != 2) { - condPC = parentPC; - } else { - tmp.clear(); - if (pc1 == condPC) { - m_curState = s; - } else if (pc2 == condPC) { - m_curState = f; - } else { - exit(1); - } - s2e()->getDebugStream() << "[select state: " << hexval(m_curState->getID()) << "] " - << "[selected state's PC: " << hexval(m_curState->regs()->getPc()) << "] " - << "\n"; - return *m_curState; + getDebugStream() << "[state ID: " << hexval(m_curState->getID()) << "] " + << "[pc: " << hexval(pcReturn) << "] " + << "\n"; + + bool flag = false; + for (const auto &it : m_forkStatesBak[m_pcCaller]) { + S2EExecutionState *f = it.second[0]; + S2EExecutionState *s = it.second[1]; + if (f == state || s == state) { + flag = true; + break; } } - return *state; + // getInfoStream() << "execute only this path and ID= " << hexval(state->getID()) << "\n"; + // if (!flag) { + // getInfoStream() << "select other state to execute " + // << "\n"; + // // void *cp = g_s2e->getPlugin("CorePlugin"); + // // s2e()->getExecutor()->MystateSwitchCallback(cp); + // // s2e()->getExecutor()->setCpuExitRequest(); + // } } } // namespace plugins diff --git a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h index 31d9bb7e..c1ea928a 100644 --- a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h @@ -8,12 +8,20 @@ #ifndef S2E_PLUGINS_VALIDPATHSEARCHER_H #define S2E_PLUGINS_VALIDPATHSEARCHER_H +#include +#include #include +#include +#include #include #include -#include +#include #include +#include #include +#include +#include +#include namespace s2e { namespace plugins { @@ -23,7 +31,20 @@ using PCCtxHash = uint64_t; using PerifVal = uint32_t; using PerifSize = uint32_t; -using Searchers = std::map; +struct StateItem { + S2EExecutionState *state; + bool visited; +}; + +struct StateItemCompare { + bool operator()(const StateItem &a, const StateItem &b) { + if (a.state->getID() != b.state->getID()) { + return a.state->getID() < b.state->getID(); + } else { + return a.visited < b.visited; + } + } +}; class ValidPathSearcher : public Plugin, public klee::Searcher { S2E_PLUGIN @@ -38,14 +59,12 @@ class ValidPathSearcher : public Plugin, public klee::Searcher { sigc::connection m_onStateForkConn; ARMFunctionMonitor *onARMFunctionConn; - Searchers m_searchers; - klee::Searcher *m_currentSearcher; - uint32_t m_pcCaller; uint32_t m_pcReturn; S2EExecutionState *m_curState; std::map>> m_forkStates; std::map>> m_forkStatesBak; + std::priority_queue, StateItemCompare> m_pq; public: /** @@ -77,10 +96,44 @@ class ValidPathSearcher : public Plugin, public klee::Searcher { * find the state which forked the child state with the condition pc. * * @param state s2e state - * @param condPC condition pc from Fork. + * @param forkPC condition pc from Fork. * @return */ - klee::ExecutionState &DFS(S2EExecutionState *state, uint32_t condPC); + + klee::ExecutionState &DFS(S2EExecutionState *state, uint32_t forkPC); + /** + * select a state on fork. + * + * @return + */ + virtual klee::ExecutionState &selectState(); + + /** + * update the state info in searcher. + * + * @param current + * @param addedStates + * @param removedStates + */ + virtual void update(klee::ExecutionState *current, const klee::StateSet &addedStates, + const klee::StateSet &removedStates); + + /** + * check if the searcher is empty. + * + * @return true, if + */ + virtual bool empty(); + +private: + + /** + * insert state to priority queue. + * + * @param state + * @return Ture if insert successfully + */ + bool insertToPriorityQueue(S2EExecutionState *state); }; } // namespace plugins 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/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 From 814f7195a7f87019a218ba24174a4e2d92e2779a Mon Sep 17 00:00:00 2001 From: hwk2077 Date: Tue, 9 May 2023 10:52:10 +0800 Subject: [PATCH 10/15] tmp --- libs2ecore/include/s2e/S2EExecutor.h | 2 + libs2ecore/src/S2EExecutor.cpp | 18 +++ .../Plugins/Searchers/ValidPathSearcher.cpp | 138 ++++++++++-------- .../s2e/Plugins/Searchers/ValidPathSearcher.h | 49 ++----- .../s2e/Plugins/uEmu/ARMFunctionMonitor.cpp | 2 +- .../src/s2e/Plugins/uEmu/ARMFunctionMonitor.h | 3 +- .../Plugins/uEmu/PeripheralModelLearning.cpp | 2 +- .../Plugins/uEmu/PeripheralModelLearning.h | 2 +- 8 files changed, 114 insertions(+), 102 deletions(-) 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/S2EExecutor.cpp b/libs2ecore/src/S2EExecutor.cpp index 7be40c44..fc023a4d 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; + } + } +} + + 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); diff --git a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp index 899cb365..57544f0d 100644 --- a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp @@ -17,14 +17,6 @@ namespace plugins { S2E_DEFINE_PLUGIN(ValidPathSearcher, "ValidPathSearcher S2E plugin", "ValidPathSearcher", "ARMFunctionMonitor"); -bool ValidPathSearcher::insertToPriorityQueue(S2EExecutionState *state) { - if (!m_pq.empty() && m_pq.top().state->getID() >= state->getID()) { - return false; - } - m_pq.push({state, false}); - return true; -} - void ValidPathSearcher::initialize() { s2e()->getExecutor()->setSearcher(this); m_onStateForkConn = @@ -35,6 +27,23 @@ void ValidPathSearcher::initialize() { onARMFunctionConn->onARMFunctionReturnEvent.connect(sigc::mem_fun(*this, &ValidPathSearcher::onARMFunctionReturn)); m_curState = nullptr; + m_selfSwitch = false; + m_searcherActive = false; +} + +bool ValidPathSearcher::insertToForkStates(uint32_t callerPC, uint32_t forkPC, S2EExecutionState *state) { + const auto &foundSameCallerPC = m_forkStateItems.find(callerPC); + if (foundSameCallerPC != m_forkStateItems.end()) { + const auto &foundSameForkPC = foundSameCallerPC->second.find(forkPC); + if (foundSameForkPC != foundSameCallerPC->second.end()) { + if (foundSameForkPC->second.size() >= 2) { + return false; + } + } + } + m_forkStateItems[callerPC][forkPC].push_back(state); + m_idStateMap[state->getID()] = {state, forkPC, 0}; + return true; } void ValidPathSearcher::onStateFork(S2EExecutionState *state, const std::vector &newStates, @@ -42,40 +51,48 @@ void ValidPathSearcher::onStateFork(S2EExecutionState *state, const std::vector< getDebugStream() << "onStateFork" << '\n'; uint32_t forkPC = state->regs()->getPc(); - S2EExecutionState *first, *second; - first = newStates[0]; - second = newStates[1]; getDebugStream() << "[forkPC: " << hexval(forkPC) << "] " << "[stateID: " << hexval(state->getID()) << "] " << "[new stateID: " << hexval(newStates[0]->getID()) << "] " << "[new stateID: " << hexval(newStates[1]->getID()) << "] " << "\n"; - - insertToPriorityQueue(newStates[0]); - insertToPriorityQueue(newStates[1]); - getDebugStream() << "[top stateID: " << hexval(m_pq.top().state->getID()) << "] " - << "\n"; - - m_forkStates[m_pcCaller][forkPC].push_back(first); - m_forkStates[m_pcCaller][forkPC].push_back(second); - m_forkStatesBak[m_pcCaller][forkPC].push_back(first); - m_forkStatesBak[m_pcCaller][forkPC].push_back(second); + insertToForkStates(m_callerPC, forkPC, newStates[0]); + insertToForkStates(m_callerPC, forkPC, newStates[1]); + m_searcherActive = true; } klee::ExecutionState &ValidPathSearcher::selectState() { getDebugStream() << "selectState" << "\n"; - while (!m_pq.empty()) { - if (m_pq.top().visited == true) { - m_pq.pop(); - continue; - } - m_curState = m_pq.top().state; - m_pq.pop(); - getDebugStream() << "[selected stateID: " << m_curState->getID() << "] " + + if (m_selfSwitch) { + m_selfSwitch = false; + m_idStateMap[m_curState->getID()].flag = 2; + getDebugStream() << "[self switch, stateID: " << m_curState->getID() << "] " << "\n"; return *m_curState; } + + // flag 0 firstly + for (auto it = m_idStateMap.rbegin(); it != m_idStateMap.rend(); ++it) { + if (it->second.flag == 0) { + it->second.flag = 2; + m_curState = it->second.state; + getDebugStream() << "[flag 0: selected stateID: " << m_curState->getID() << "] " + << "\n"; + return *m_curState; + } + } + // flag 2 secondly + // for (auto it = m_idStateMap.rbegin(); it != m_idStateMap.rend(); ++it) { + // if (it->second.flag == 2) { + // m_curState = it->second.state; + // getDebugStream() << "[flag 2: selected stateID: " << m_curState->getID() << "] " + // << "\n"; + // return *m_curState; + // } + // } + getDebugStream() << "[no option, stateID: " << m_curState->getID() << "] " << "\n"; return *m_curState; @@ -83,19 +100,11 @@ klee::ExecutionState &ValidPathSearcher::selectState() { void ValidPathSearcher::update(klee::ExecutionState *current, const klee::StateSet &addedStates, const klee::StateSet &removedStates) { - // getDebugStream() << "update" - // << "\n"; for (auto it : removedStates) { S2EExecutionState *removedState = static_cast(it); - auto it2 = m_forkStates[m_pcCaller].begin(); - for (; it2 != m_forkStates[m_pcCaller].end(); it2++) { - S2EExecutionState *f = it2->second[0]; - S2EExecutionState *s = it2->second[1]; - if (f == removedState) { - (it2->second).erase((it2->second).begin()); - } else if (s == removedState) { - (it2->second).erase((it2->second).begin() + 1); - } + auto found = m_idStateMap.find(removedState->getID()); + if (found != m_idStateMap.end()) { + found->second.flag = 1; } } } @@ -103,15 +112,23 @@ void ValidPathSearcher::update(klee::ExecutionState *current, const klee::StateS bool ValidPathSearcher::empty() { getDebugStream() << "empty" << "\n"; - return m_pq.empty(); + for (const auto &it : m_idStateMap) { + if (it.second.flag == 0 || it.second.flag == 2) { + return false; + } + } + return true; } -void ValidPathSearcher::onARMFunctionCall(S2EExecutionState *state, uint32_t pcCaller, uint64_t pcCtxHashVal) { +void ValidPathSearcher::onARMFunctionCall(S2EExecutionState *state, uint32_t pcCaller, uint64_t pcCtxHashVal, + uint32_t pcReturn) { getDebugStream() << "onARMFunctionCall" << "\n"; + m_callerPC = pcCaller; + m_functionCalRetMap[pcReturn] = pcCaller; - m_pcCaller = pcCaller; - getDebugStream() << "[record call pc: " << hexval(pcCaller) << "] " + getDebugStream() << "[caller pc: " << hexval(pcCaller) << "] " + << "[return pc: " << hexval(pcReturn) << "] " << "[pc and context hash: " << hexval(pcCtxHashVal) << "] " << "\n"; } @@ -121,28 +138,23 @@ void ValidPathSearcher::onARMFunctionReturn(S2EExecutionState *state, uint32_t p getDebugStream() << "onARMFunctionReturn" << "\n"; m_curState = state; - m_pcReturn = pcReturn; - getDebugStream() << "[state ID: " << hexval(m_curState->getID()) << "] " - << "[pc: " << hexval(pcReturn) << "] " - << "\n"; + m_returnPC = pcReturn; - bool flag = false; - for (const auto &it : m_forkStatesBak[m_pcCaller]) { - S2EExecutionState *f = it.second[0]; - S2EExecutionState *s = it.second[1]; - if (f == state || s == state) { - flag = true; - break; + if (!m_searcherActive) { + return; + } + uint32_t callerPC = m_functionCalRetMap[m_returnPC]; + uint32_t forkPC = m_idStateMap[state->getID()].forkPC; + + for (auto &it : m_forkStateItems[callerPC][forkPC]) { + if (m_idStateMap[it->getID()].flag == 0) { + m_selfSwitch = true; + m_curState = m_idStateMap[it->getID()].state; + void *cp = g_s2e->getPlugin("CorePlugin"); + s2e()->getExecutor()->validPathSearcherStateSwitchCallback(cp); + s2e()->getExecutor()->setCpuExitRequest(); } } - // getInfoStream() << "execute only this path and ID= " << hexval(state->getID()) << "\n"; - // if (!flag) { - // getInfoStream() << "select other state to execute " - // << "\n"; - // // void *cp = g_s2e->getPlugin("CorePlugin"); - // // s2e()->getExecutor()->MystateSwitchCallback(cp); - // // s2e()->getExecutor()->setCpuExitRequest(); - // } } } // namespace plugins diff --git a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h index c1ea928a..e4e1b59c 100644 --- a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h @@ -33,17 +33,8 @@ using PerifSize = uint32_t; struct StateItem { S2EExecutionState *state; - bool visited; -}; - -struct StateItemCompare { - bool operator()(const StateItem &a, const StateItem &b) { - if (a.state->getID() != b.state->getID()) { - return a.state->getID() < b.state->getID(); - } else { - return a.visited < b.visited; - } - } + uint32_t forkPC; + uint32_t flag; }; class ValidPathSearcher : public Plugin, public klee::Searcher { @@ -59,12 +50,15 @@ class ValidPathSearcher : public Plugin, public klee::Searcher { sigc::connection m_onStateForkConn; ARMFunctionMonitor *onARMFunctionConn; - uint32_t m_pcCaller; - uint32_t m_pcReturn; + uint32_t m_callerPC; + uint32_t m_returnPC; S2EExecutionState *m_curState; - std::map>> m_forkStates; - std::map>> m_forkStatesBak; - std::priority_queue, StateItemCompare> m_pq; + bool m_selfSwitch; + bool m_searcherActive; + + std::map>> m_forkStateItems; + std::map m_idStateMap; + std::map m_functionCalRetMap; public: /** @@ -81,8 +75,9 @@ class ValidPathSearcher : public Plugin, public klee::Searcher { * @param state s2e state * @param pcCaller pc of caller * @param pcCtxHashVal pc and context hash value + * @param pcReturn pc of return */ - void onARMFunctionCall(S2EExecutionState *state, uint32_t pcCaller, uint64_t pcCtxHashVal); + void onARMFunctionCall(S2EExecutionState *state, uint32_t pcCaller, uint64_t pcCtxHashVal, uint32_t pcReturn); /** * callback when function return. @@ -92,15 +87,6 @@ class ValidPathSearcher : public Plugin, public klee::Searcher { */ void onARMFunctionReturn(S2EExecutionState *state, uint32_t pcReturn); - /** - * find the state which forked the child state with the condition pc. - * - * @param state s2e state - * @param forkPC condition pc from Fork. - * @return - */ - - klee::ExecutionState &DFS(S2EExecutionState *state, uint32_t forkPC); /** * select a state on fork. * @@ -109,7 +95,7 @@ class ValidPathSearcher : public Plugin, public klee::Searcher { virtual klee::ExecutionState &selectState(); /** - * update the state info in searcher. + * update the state info in searcher.m_idStateMap * * @param current * @param addedStates @@ -126,14 +112,7 @@ class ValidPathSearcher : public Plugin, public klee::Searcher { virtual bool empty(); private: - - /** - * insert state to priority queue. - * - * @param state - * @return Ture if insert successfully - */ - bool insertToPriorityQueue(S2EExecutionState *state); + bool insertToForkStates(uint32_t callerPC, uint32_t forkPC, S2EExecutionState *state); }; } // namespace plugins 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/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); }; From 5f103873415b52f26a9ca2b8de41a4db3c561f98 Mon Sep 17 00:00:00 2001 From: Wenkang Huang Date: Fri, 8 Sep 2023 16:19:00 +0800 Subject: [PATCH 11/15] chore: replace magic value with enum --- .../Plugins/Searchers/ValidPathSearcher.cpp | 110 ++++++++++-------- .../s2e/Plugins/Searchers/ValidPathSearcher.h | 17 +++ 2 files changed, 78 insertions(+), 49 deletions(-) diff --git a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp index 57544f0d..f380b0bc 100644 --- a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp @@ -21,6 +21,8 @@ void ValidPathSearcher::initialize() { s2e()->getExecutor()->setSearcher(this); 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)); @@ -31,67 +33,35 @@ void ValidPathSearcher::initialize() { m_searcherActive = false; } -bool ValidPathSearcher::insertToForkStates(uint32_t callerPC, uint32_t forkPC, S2EExecutionState *state) { - const auto &foundSameCallerPC = m_forkStateItems.find(callerPC); - if (foundSameCallerPC != m_forkStateItems.end()) { - const auto &foundSameForkPC = foundSameCallerPC->second.find(forkPC); - if (foundSameForkPC != foundSameCallerPC->second.end()) { - if (foundSameForkPC->second.size() >= 2) { - return false; - } - } - } - m_forkStateItems[callerPC][forkPC].push_back(state); - m_idStateMap[state->getID()] = {state, forkPC, 0}; - return true; -} - -void ValidPathSearcher::onStateFork(S2EExecutionState *state, const std::vector &newStates, - const std::vector> &newConditions) { - getDebugStream() << "onStateFork" << '\n'; - - uint32_t forkPC = state->regs()->getPc(); - getDebugStream() << "[forkPC: " << hexval(forkPC) << "] " - << "[stateID: " << hexval(state->getID()) << "] " - << "[new stateID: " << hexval(newStates[0]->getID()) << "] " - << "[new stateID: " << hexval(newStates[1]->getID()) << "] " - << "\n"; - insertToForkStates(m_callerPC, forkPC, newStates[0]); - insertToForkStates(m_callerPC, forkPC, newStates[1]); - m_searcherActive = true; -} - klee::ExecutionState &ValidPathSearcher::selectState() { getDebugStream() << "selectState" << "\n"; if (m_selfSwitch) { m_selfSwitch = false; - m_idStateMap[m_curState->getID()].flag = 2; + m_idStateMap[m_curState->getID()].flag = VALID; getDebugStream() << "[self switch, stateID: " << m_curState->getID() << "] " << "\n"; return *m_curState; } - // flag 0 firstly for (auto it = m_idStateMap.rbegin(); it != m_idStateMap.rend(); ++it) { - if (it->second.flag == 0) { - it->second.flag = 2; + if (it->second.flag == UNVISITED) { + it->second.flag = VALID; m_curState = it->second.state; - getDebugStream() << "[flag 0: selected stateID: " << m_curState->getID() << "] " + getDebugStream() << "[selected unvisited stateID: " << m_curState->getID() << "] " + << "\n"; + return *m_curState; + } + } + for (auto it = m_idStateMap.rbegin(); it != m_idStateMap.rend(); ++it) { + if (it->second.flag == VALID) { + m_curState = it->second.state; + getDebugStream() << "[selected valid stateID: " << m_curState->getID() << "] " << "\n"; return *m_curState; } } - // flag 2 secondly - // for (auto it = m_idStateMap.rbegin(); it != m_idStateMap.rend(); ++it) { - // if (it->second.flag == 2) { - // m_curState = it->second.state; - // getDebugStream() << "[flag 2: selected stateID: " << m_curState->getID() << "] " - // << "\n"; - // return *m_curState; - // } - // } getDebugStream() << "[no option, stateID: " << m_curState->getID() << "] " << "\n"; @@ -104,22 +74,62 @@ void ValidPathSearcher::update(klee::ExecutionState *current, const klee::StateS S2EExecutionState *removedState = static_cast(it); auto found = m_idStateMap.find(removedState->getID()); if (found != m_idStateMap.end()) { - found->second.flag = 1; + found->second.flag = INVALID; } } } bool ValidPathSearcher::empty() { - getDebugStream() << "empty" - << "\n"; for (const auto &it : m_idStateMap) { - if (it.second.flag == 0 || it.second.flag == 2) { + if (it.second.flag == UNVISITED || it.second.flag == VALID) { + getDebugStream() << "empty" + << "\n"; return false; } } return true; } +bool ValidPathSearcher::insertToForkStates(uint32_t callerPC, uint32_t forkPC, S2EExecutionState *state) { + const auto &foundSameCallerPC = m_forkStateItems.find(callerPC); + if (foundSameCallerPC != m_forkStateItems.end()) { + const auto &foundSameForkPC = foundSameCallerPC->second.find(forkPC); + if (foundSameForkPC != foundSameCallerPC->second.end()) { + if (foundSameForkPC->second.size() >= 2) { + return false; + } + } + } + m_forkStateItems[callerPC][forkPC].push_back(state); + m_idStateMap[state->getID()] = {state, forkPC, UNVISITED}; + return true; +} + +void ValidPathSearcher::onStateFork(S2EExecutionState *state, const std::vector &newStates, + const std::vector> &newConditions) { + getDebugStream() << "onStateFork" << '\n'; + + uint32_t forkPC = state->regs()->getPc(); + getDebugStream() << "[forkPC: " << hexval(forkPC) << "] " + << "[stateID: " << hexval(state->getID()) << "] " + << "[new stateID: " << hexval(newStates[0]->getID()) << "] " + << "[new stateID: " << hexval(newStates[1]->getID()) << "] " + << "\n"; + insertToForkStates(m_callerPC, forkPC, newStates[0]); + insertToForkStates(m_callerPC, forkPC, newStates[1]); + m_idStateMap[state->getID()].flag = VALID; + m_searcherActive = true; +} + +void ValidPathSearcher::onTranslateBlockEnd(ExecutionSignal *signal, S2EExecutionState *state, TranslationBlock *tb, + uint64_t pc, bool isStatic, uint64_t staticTargetPc) { + getDebugStream() << "onTranslateBlockEnd" << '\n'; + + m_tbNum++; + getDebugStream() << "[the number of blocks: " << m_tbNum << "]" + << "\n"; +} + void ValidPathSearcher::onARMFunctionCall(S2EExecutionState *state, uint32_t pcCaller, uint64_t pcCtxHashVal, uint32_t pcReturn) { getDebugStream() << "onARMFunctionCall" @@ -147,9 +157,11 @@ void ValidPathSearcher::onARMFunctionReturn(S2EExecutionState *state, uint32_t p uint32_t forkPC = m_idStateMap[state->getID()].forkPC; for (auto &it : m_forkStateItems[callerPC][forkPC]) { - if (m_idStateMap[it->getID()].flag == 0) { + if (m_idStateMap[it->getID()].flag == INVALID) { m_selfSwitch = true; m_curState = m_idStateMap[it->getID()].state; + getDebugStream() << "self switch" + << "\n"; void *cp = g_s2e->getPlugin("CorePlugin"); s2e()->getExecutor()->validPathSearcherStateSwitchCallback(cp); s2e()->getExecutor()->setCpuExitRequest(); diff --git a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h index e4e1b59c..cdaf6888 100644 --- a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h @@ -37,6 +37,8 @@ struct StateItem { uint32_t flag; }; +enum StatePhase { UNVISITED, INVALID, VALID }; + class ValidPathSearcher : public Plugin, public klee::Searcher { S2E_PLUGIN @@ -48,8 +50,10 @@ class ValidPathSearcher : public Plugin, public klee::Searcher { private: sigc::connection m_onStateForkConn; + sigc::connection m_onTranslateBlockEndConn; ARMFunctionMonitor *onARMFunctionConn; + uint32_t m_tbNum; uint32_t m_callerPC; uint32_t m_returnPC; S2EExecutionState *m_curState; @@ -69,6 +73,19 @@ class ValidPathSearcher : public Plugin, public klee::Searcher { */ void onStateFork(S2EExecutionState *state, const std::vector &newStates, const std::vector> &newConditions); + + /** + * + * @param signal + * @param state + * @param tb + * @param pc + * @param isStatic + * @param staticTargetPc + */ + void onTranslateBlockEnd(ExecutionSignal *signal, S2EExecutionState *state, TranslationBlock *tb, uint64_t pc, + bool isStatic, uint64_t staticTargetPc); + /** * callback when function call. * From ba40e4d39aa9d0aaf9bcd1bf79c0bd707588746d Mon Sep 17 00:00:00 2001 From: hwk2077 Date: Fri, 8 Sep 2023 19:26:29 +0800 Subject: [PATCH 12/15] feat: self switch --- .../Plugins/Searchers/ValidPathSearcher.cpp | 123 ++++++++++++------ .../s2e/Plugins/Searchers/ValidPathSearcher.h | 1 + 2 files changed, 87 insertions(+), 37 deletions(-) diff --git a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp index f380b0bc..c3216510 100644 --- a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp @@ -29,65 +29,113 @@ void ValidPathSearcher::initialize() { onARMFunctionConn->onARMFunctionReturnEvent.connect(sigc::mem_fun(*this, &ValidPathSearcher::onARMFunctionReturn)); m_curState = nullptr; + m_lstState = nullptr; m_selfSwitch = false; m_searcherActive = false; } klee::ExecutionState &ValidPathSearcher::selectState() { - getDebugStream() << "selectState" + getDebugStream() << "selectState " + << "[current stateID: " << m_curState->getID() << "] " << "\n"; if (m_selfSwitch) { m_selfSwitch = false; - m_idStateMap[m_curState->getID()].flag = VALID; - getDebugStream() << "[self switch, stateID: " << m_curState->getID() << "] " + uint32_t callerPC = m_functionCalRetMap[m_returnPC]; + uint32_t forkPC = m_idStateMap[m_curState->getID()].forkPC; + getDebugStream() << "self switch " + << "[callerPC: " << hexval(callerPC) << "] " + << "[forkPC: " << hexval(forkPC) << "] " + << "\n"; + for (auto &it : m_forkStateItems[callerPC][forkPC]) { + if (it->getID() != m_curState->getID() && m_idStateMap[it->getID()].flag != INVALID) { + m_idStateMap[it->getID()].flag = VALID; + m_lstState = m_curState; + m_curState = m_idStateMap[it->getID()].state; + if (m_curState == nullptr) { + getDebugStream() << "m_curState is nullptr" + << "\n"; + } + getDebugStream() << "[new self-switched StateID: " << m_curState->getID() << "] " + << "\n"; + return *m_curState; + } + } + getDebugStream() << "no option for self switch" << "\n"; return *m_curState; } for (auto it = m_idStateMap.rbegin(); it != m_idStateMap.rend(); ++it) { - if (it->second.flag == UNVISITED) { + if (it->second.state->getID() != m_curState->getID() && it->second.state != m_lstState && + it->second.flag == UNVISITED) { it->second.flag = VALID; m_curState = it->second.state; - getDebugStream() << "[selected unvisited stateID: " << m_curState->getID() << "] " + if (m_curState == nullptr) { + getDebugStream() << "m_curState is nullptr" + << "\n"; + } + getDebugStream() << "[new selected unvisited stateID: " << m_curState->getID() << "] " << "\n"; + m_lstState = m_curState; return *m_curState; } } for (auto it = m_idStateMap.rbegin(); it != m_idStateMap.rend(); ++it) { - if (it->second.flag == VALID) { + if (it->second.state->getID() != m_curState->getID() && it->second.state != m_lstState && + it->second.flag == VALID) { m_curState = it->second.state; - getDebugStream() << "[selected valid stateID: " << m_curState->getID() << "] " + if (m_curState == nullptr) { + getDebugStream() << "m_curState is nullptr" + << "\n"; + } + m_lstState = m_curState; + getDebugStream() << "[new selected valid stateID: " << m_curState->getID() << "] " << "\n"; return *m_curState; } } - getDebugStream() << "[no option, stateID: " << m_curState->getID() << "] " + getDebugStream() << "no option" << "\n"; return *m_curState; } void ValidPathSearcher::update(klee::ExecutionState *current, const klee::StateSet &addedStates, const klee::StateSet &removedStates) { + // if (m_curState) { + // getDebugStream() << "update " + // << "[current stateID: " << m_curState->getID() << "] " + // << "\n"; + // } else { + // getDebugStream() << "update " + // << "\n"; + // } for (auto it : removedStates) { - S2EExecutionState *removedState = static_cast(it); + S2EExecutionState *removedState = dynamic_cast(it); auto found = m_idStateMap.find(removedState->getID()); if (found != m_idStateMap.end()) { found->second.flag = INVALID; + getDebugStream() << "[invalid stateID: " << found->second.state->getID() << "] " + << "\n"; } } + // for (auto it : m_idStateMap) { + // getDebugStream() << "[traversal stateID: " << it.second.state->getID() << "] " + // << "[flag: " << it.second.flag << "] " + // << "\n"; + // } } bool ValidPathSearcher::empty() { - for (const auto &it : m_idStateMap) { - if (it.second.flag == UNVISITED || it.second.flag == VALID) { - getDebugStream() << "empty" - << "\n"; - return false; - } - } - return true; + // for (const auto &it : m_idStateMap) { + // if (it.second.flag == UNVISITED || it.second.flag == VALID) { + // getDebugStream() << "empty" + // << "\n"; + // return false; + // } + // } + return false; } bool ValidPathSearcher::insertToForkStates(uint32_t callerPC, uint32_t forkPC, S2EExecutionState *state) { @@ -112,8 +160,8 @@ void ValidPathSearcher::onStateFork(S2EExecutionState *state, const std::vector< uint32_t forkPC = state->regs()->getPc(); getDebugStream() << "[forkPC: " << hexval(forkPC) << "] " << "[stateID: " << hexval(state->getID()) << "] " - << "[new stateID: " << hexval(newStates[0]->getID()) << "] " - << "[new stateID: " << hexval(newStates[1]->getID()) << "] " + << "[new stateID: " << newStates[0]->getID() << "] " + << "[new stateID: " << newStates[1]->getID() << "] " << "\n"; insertToForkStates(m_callerPC, forkPC, newStates[0]); insertToForkStates(m_callerPC, forkPC, newStates[1]); @@ -123,11 +171,11 @@ void ValidPathSearcher::onStateFork(S2EExecutionState *state, const std::vector< void ValidPathSearcher::onTranslateBlockEnd(ExecutionSignal *signal, S2EExecutionState *state, TranslationBlock *tb, uint64_t pc, bool isStatic, uint64_t staticTargetPc) { - getDebugStream() << "onTranslateBlockEnd" << '\n'; - + // getDebugStream() << "onTranslateBlockEnd" << '\n'; + // m_tbNum++; - getDebugStream() << "[the number of blocks: " << m_tbNum << "]" - << "\n"; + // getDebugStream() << "[the number of blocks: " << m_tbNum << "]" + // << "\n"; } void ValidPathSearcher::onARMFunctionCall(S2EExecutionState *state, uint32_t pcCaller, uint64_t pcCtxHashVal, @@ -153,20 +201,21 @@ void ValidPathSearcher::onARMFunctionReturn(S2EExecutionState *state, uint32_t p if (!m_searcherActive) { return; } - uint32_t callerPC = m_functionCalRetMap[m_returnPC]; - uint32_t forkPC = m_idStateMap[state->getID()].forkPC; - - for (auto &it : m_forkStateItems[callerPC][forkPC]) { - if (m_idStateMap[it->getID()].flag == INVALID) { - m_selfSwitch = true; - m_curState = m_idStateMap[it->getID()].state; - getDebugStream() << "self switch" - << "\n"; - void *cp = g_s2e->getPlugin("CorePlugin"); - s2e()->getExecutor()->validPathSearcherStateSwitchCallback(cp); - s2e()->getExecutor()->setCpuExitRequest(); - } - } + + // m_selfSwitch = true; + // // s2e()->getExecutor()->selectNextState(m_curState); + // s2e()->getExecutor()->suspendState(m_curState); + + // uint32_t callerPC = m_functionCalRetMap[m_returnPC]; + // uint32_t forkPC = m_idStateMap[state->getID()].forkPC; + // for (auto &it : m_forkStateItems[callerPC][forkPC]) { + // if (m_idStateMap[it->getID()].state->getID() != m_curState->getID() && + // m_idStateMap[it->getID()].flag != INVALID) { + // m_selfSwitch = true; + // m_curState = m_idStateMap[it->getID()].state; + // s2e()->getExecutor()->selectNextState(m_curState); + // } + // } } } // namespace plugins diff --git a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h index cdaf6888..e37555e2 100644 --- a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h @@ -57,6 +57,7 @@ class ValidPathSearcher : public Plugin, public klee::Searcher { uint32_t m_callerPC; uint32_t m_returnPC; S2EExecutionState *m_curState; + S2EExecutionState *m_lstState; bool m_selfSwitch; bool m_searcherActive; From 790977b98d0a8519f172bc9f8c9281fbbd806b10 Mon Sep 17 00:00:00 2001 From: hwk2077 Date: Mon, 11 Sep 2023 19:36:49 +0800 Subject: [PATCH 13/15] chore: refactor --- .../Plugins/Searchers/ValidPathSearcher.cpp | 222 ++++++++++-------- .../s2e/Plugins/Searchers/ValidPathSearcher.h | 66 +----- 2 files changed, 130 insertions(+), 158 deletions(-) diff --git a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp index c3216510..a682904e 100644 --- a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp @@ -19,17 +19,8 @@ S2E_DEFINE_PLUGIN(ValidPathSearcher, "ValidPathSearcher S2E plugin", "ValidPathS void ValidPathSearcher::initialize() { s2e()->getExecutor()->setSearcher(this); - 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)); - + initConnection(); m_curState = nullptr; - m_lstState = nullptr; m_selfSwitch = false; m_searcherActive = false; } @@ -41,59 +32,14 @@ klee::ExecutionState &ValidPathSearcher::selectState() { if (m_selfSwitch) { m_selfSwitch = false; - uint32_t callerPC = m_functionCalRetMap[m_returnPC]; - uint32_t forkPC = m_idStateMap[m_curState->getID()].forkPC; - getDebugStream() << "self switch " - << "[callerPC: " << hexval(callerPC) << "] " - << "[forkPC: " << hexval(forkPC) << "] " - << "\n"; - for (auto &it : m_forkStateItems[callerPC][forkPC]) { - if (it->getID() != m_curState->getID() && m_idStateMap[it->getID()].flag != INVALID) { - m_idStateMap[it->getID()].flag = VALID; - m_lstState = m_curState; - m_curState = m_idStateMap[it->getID()].state; - if (m_curState == nullptr) { - getDebugStream() << "m_curState is nullptr" - << "\n"; - } - getDebugStream() << "[new self-switched StateID: " << m_curState->getID() << "] " - << "\n"; - return *m_curState; - } - } - getDebugStream() << "no option for self switch" - << "\n"; + selectSelfSwitchedState(); return *m_curState; } - - for (auto it = m_idStateMap.rbegin(); it != m_idStateMap.rend(); ++it) { - if (it->second.state->getID() != m_curState->getID() && it->second.state != m_lstState && - it->second.flag == UNVISITED) { - it->second.flag = VALID; - m_curState = it->second.state; - if (m_curState == nullptr) { - getDebugStream() << "m_curState is nullptr" - << "\n"; - } - getDebugStream() << "[new selected unvisited stateID: " << m_curState->getID() << "] " - << "\n"; - m_lstState = m_curState; - return *m_curState; - } + if (selectUnvisitedState()) { + return *m_curState; } - for (auto it = m_idStateMap.rbegin(); it != m_idStateMap.rend(); ++it) { - if (it->second.state->getID() != m_curState->getID() && it->second.state != m_lstState && - it->second.flag == VALID) { - m_curState = it->second.state; - if (m_curState == nullptr) { - getDebugStream() << "m_curState is nullptr" - << "\n"; - } - m_lstState = m_curState; - getDebugStream() << "[new selected valid stateID: " << m_curState->getID() << "] " - << "\n"; - return *m_curState; - } + if (selectValidState()) { + return *m_curState; } getDebugStream() << "no option" @@ -103,14 +49,6 @@ klee::ExecutionState &ValidPathSearcher::selectState() { void ValidPathSearcher::update(klee::ExecutionState *current, const klee::StateSet &addedStates, const klee::StateSet &removedStates) { - // if (m_curState) { - // getDebugStream() << "update " - // << "[current stateID: " << m_curState->getID() << "] " - // << "\n"; - // } else { - // getDebugStream() << "update " - // << "\n"; - // } for (auto it : removedStates) { S2EExecutionState *removedState = dynamic_cast(it); auto found = m_idStateMap.find(removedState->getID()); @@ -120,11 +58,6 @@ void ValidPathSearcher::update(klee::ExecutionState *current, const klee::StateS << "\n"; } } - // for (auto it : m_idStateMap) { - // getDebugStream() << "[traversal stateID: " << it.second.state->getID() << "] " - // << "[flag: " << it.second.flag << "] " - // << "\n"; - // } } bool ValidPathSearcher::empty() { @@ -138,26 +71,11 @@ bool ValidPathSearcher::empty() { return false; } -bool ValidPathSearcher::insertToForkStates(uint32_t callerPC, uint32_t forkPC, S2EExecutionState *state) { - const auto &foundSameCallerPC = m_forkStateItems.find(callerPC); - if (foundSameCallerPC != m_forkStateItems.end()) { - const auto &foundSameForkPC = foundSameCallerPC->second.find(forkPC); - if (foundSameForkPC != foundSameCallerPC->second.end()) { - if (foundSameForkPC->second.size() >= 2) { - return false; - } - } - } - m_forkStateItems[callerPC][forkPC].push_back(state); - m_idStateMap[state->getID()] = {state, forkPC, UNVISITED}; - return true; -} - void ValidPathSearcher::onStateFork(S2EExecutionState *state, const std::vector &newStates, const std::vector> &newConditions) { getDebugStream() << "onStateFork" << '\n'; - uint32_t forkPC = state->regs()->getPc(); + const uint32_t forkPC = state->regs()->getPc(); getDebugStream() << "[forkPC: " << hexval(forkPC) << "] " << "[stateID: " << hexval(state->getID()) << "] " << "[new stateID: " << newStates[0]->getID() << "] " @@ -203,19 +121,119 @@ void ValidPathSearcher::onARMFunctionReturn(S2EExecutionState *state, uint32_t p } // m_selfSwitch = true; - // // s2e()->getExecutor()->selectNextState(m_curState); - // s2e()->getExecutor()->suspendState(m_curState); - - // uint32_t callerPC = m_functionCalRetMap[m_returnPC]; - // uint32_t forkPC = m_idStateMap[state->getID()].forkPC; - // for (auto &it : m_forkStateItems[callerPC][forkPC]) { - // if (m_idStateMap[it->getID()].state->getID() != m_curState->getID() && - // m_idStateMap[it->getID()].flag != INVALID) { - // m_selfSwitch = true; - // m_curState = m_idStateMap[it->getID()].state; - // s2e()->getExecutor()->selectNextState(m_curState); - // } - // } + + if (m_selfSwitch) { + getDebugStream() << "[states' size " << s2e()->getExecutor()->getStatesCount() << "] " + << "\n"; + + if (g_s2e_state) { + S2EExecutionState *nextState = s2e()->getExecutor()->selectNextState(g_s2e_state); + if (nextState) { + g_s2e_state = nextState; + + } else { + // Do not reschedule the timer anymore + return; + } + } + getDebugStream() << "[states' size " << s2e()->getExecutor()->getStatesCount() << "] " + << "\n"; + + // s2e()->getExecutor()->selectSearcherState(m_curState) + // s2e()->getExecutor()->selectNextState(m_curState); + // s2e()->getExecutor()->suspendState(m_curState); + // s2e()->getExecutor()->setCpuExitRequest(); + } +} + +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::insertToForkStates(const uint32_t callerPC, const uint32_t forkPC, S2EExecutionState *state) { + const auto &foundSameCallerPC = m_forkStateItems.find(callerPC); + if (foundSameCallerPC != m_forkStateItems.end()) { + const auto &foundSameForkPC = foundSameCallerPC->second.find(forkPC); + if (foundSameForkPC != foundSameCallerPC->second.end()) { + if (foundSameForkPC->second.size() >= 2) { + return false; + } + } + } + m_forkStateItems[callerPC][forkPC].push_back(state); + m_idStateMap[state->getID()] = {state, forkPC, UNVISITED, 0}; + return true; +} + +bool ValidPathSearcher::selectSelfSwitchedState() { + const uint32_t callerPC = m_functionCalRetMap[m_returnPC]; + const uint32_t forkPC = m_idStateMap[m_curState->getID()].forkPC; + getDebugStream() << "self switch " + << "[callerPC: " << hexval(callerPC) << "] " + << "[forkPC: " << hexval(forkPC) << "] " + << "\n"; + + for (auto &it : m_forkStateItems[callerPC][forkPC]) { + const int id = it->getID(); + if (m_curState->getID() != id && m_idStateMap[id].flag != INVALID) { + if (m_idStateMap[id].switchCnt >= MAX_SWITCH_CNT) { + m_idStateMap[id].flag = INVALID; + continue; + } + m_idStateMap[id].switchCnt++; + m_idStateMap[id].flag = VALID; + m_curState = m_idStateMap[id].state; + getDebugStream() << "[new self-switched StateID: " << m_curState->getID() << "] " + << "\n"; + return true; + } + } + + getDebugStream() << "no option for self switch" + << "\n"; + return false; +} + +bool ValidPathSearcher::selectUnvisitedState() { + for (auto it = m_idStateMap.rbegin(); it != m_idStateMap.rend(); ++it) { + if (it->second.state->getID() != m_curState->getID() && it->second.flag == UNVISITED) { + if (it->second.switchCnt >= MAX_SWITCH_CNT) { + it->second.flag = INVALID; + continue; + } + it->second.switchCnt++; + it->second.flag = VALID; + m_curState = it->second.state; + getDebugStream() << "[new selected unvisited stateID: " << m_curState->getID() << "] " + << "\n"; + return true; + } + } + return false; +} + +bool ValidPathSearcher::selectValidState() { + for (auto it = m_idStateMap.rbegin(); it != m_idStateMap.rend(); ++it) { + if (it->second.state->getID() != m_curState->getID() && it->second.flag == VALID) { + if (it->second.switchCnt >= MAX_SWITCH_CNT) { + it->second.flag = INVALID; + continue; + } + it->second.switchCnt++; + m_curState = it->second.state; + getDebugStream() << "[new selected valid stateID: " << m_curState->getID() << "] " + << "\n"; + return true; + } + } + return false; } } // namespace plugins diff --git a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h index e37555e2..2309f310 100644 --- a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h @@ -35,9 +35,11 @@ struct StateItem { S2EExecutionState *state; uint32_t forkPC; uint32_t flag; + uint32_t switchCnt; }; enum StatePhase { UNVISITED, INVALID, VALID }; +const int MAX_SWITCH_CNT = 20; class ValidPathSearcher : public Plugin, public klee::Searcher { S2E_PLUGIN @@ -57,7 +59,6 @@ class ValidPathSearcher : public Plugin, public klee::Searcher { uint32_t m_callerPC; uint32_t m_returnPC; S2EExecutionState *m_curState; - S2EExecutionState *m_lstState; bool m_selfSwitch; bool m_searcherActive; @@ -65,72 +66,25 @@ class ValidPathSearcher : public Plugin, public klee::Searcher { std::map m_idStateMap; std::map m_functionCalRetMap; -public: - /** - * callback when state fork - * @param state - * @param newStates - * @param newConditions - */ + void initConnection(); + bool insertToForkStates(const uint32_t callerPC, const uint32_t forkPC, S2EExecutionState *state); + bool selectSelfSwitchedState(); + bool selectUnvisitedState(); + bool selectValidState(); + + // callbacks void onStateFork(S2EExecutionState *state, const std::vector &newStates, const std::vector> &newConditions); - - /** - * - * @param signal - * @param state - * @param tb - * @param pc - * @param isStatic - * @param staticTargetPc - */ void onTranslateBlockEnd(ExecutionSignal *signal, S2EExecutionState *state, TranslationBlock *tb, uint64_t pc, bool isStatic, uint64_t staticTargetPc); - - /** - * callback when function call. - * - * @param state s2e state - * @param pcCaller pc of caller - * @param pcCtxHashVal pc and context hash value - * @param pcReturn pc of return - */ void onARMFunctionCall(S2EExecutionState *state, uint32_t pcCaller, uint64_t pcCtxHashVal, uint32_t pcReturn); - - /** - * callback when function return. - * - * @param state s2e state - * @param pcReturn pc of return - */ void onARMFunctionReturn(S2EExecutionState *state, uint32_t pcReturn); - /** - * select a state on fork. - * - * @return - */ +public: virtual klee::ExecutionState &selectState(); - - /** - * update the state info in searcher.m_idStateMap - * - * @param current - * @param addedStates - * @param removedStates - */ virtual void update(klee::ExecutionState *current, const klee::StateSet &addedStates, const klee::StateSet &removedStates); - - /** - * check if the searcher is empty. - * - * @return true, if - */ virtual bool empty(); - -private: - bool insertToForkStates(uint32_t callerPC, uint32_t forkPC, S2EExecutionState *state); }; } // namespace plugins From aefd65335537da9e30984ecf5af4bb825b613c18 Mon Sep 17 00:00:00 2001 From: hwk2077 Date: Tue, 12 Sep 2023 16:50:02 +0800 Subject: [PATCH 14/15] fix: switch state --- libs2ecore/src/S2EExecutor.cpp | 10 +- .../Plugins/Searchers/ValidPathSearcher.cpp | 137 ++++++++++-------- .../s2e/Plugins/Searchers/ValidPathSearcher.h | 6 +- 3 files changed, 90 insertions(+), 63 deletions(-) diff --git a/libs2ecore/src/S2EExecutor.cpp b/libs2ecore/src/S2EExecutor.cpp index fc023a4d..f9e78c7a 100644 --- a/libs2ecore/src/S2EExecutor.cpp +++ b/libs2ecore/src/S2EExecutor.cpp @@ -818,10 +818,10 @@ void S2EExecutor::stateSwitchTimerCallback(void *opaque) { void S2EExecutor::validPathSearcherStateSwitchCallback(void *opaque) { S2EExecutor *c = (S2EExecutor *) opaque; - // assert(env->current_tb == nullptr); + assert(env->current_tb == nullptr); if (g_s2e_state) { - // c->doLoadBalancing(); + c->doLoadBalancing(); S2EExecutionState *nextState = c->selectNextState(g_s2e_state); if (nextState) { g_s2e_state = nextState; @@ -830,9 +830,9 @@ void S2EExecutor::validPathSearcherStateSwitchCallback(void *opaque) { 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); @@ -1928,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/s2e/Plugins/Searchers/ValidPathSearcher.cpp b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp index a682904e..8c1ac8cf 100644 --- a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp @@ -49,13 +49,20 @@ klee::ExecutionState &ValidPathSearcher::selectState() { void ValidPathSearcher::update(klee::ExecutionState *current, const klee::StateSet &addedStates, const klee::StateSet &removedStates) { + if (!m_searcherActive) { + m_curState = dynamic_cast(current); + getDebugStream() << "[start stateID: " << m_curState->getID() << "] " + << "\n"; + m_searcherActive = true; + } + for (auto it : removedStates) { S2EExecutionState *removedState = dynamic_cast(it); auto found = m_idStateMap.find(removedState->getID()); if (found != m_idStateMap.end()) { - found->second.flag = INVALID; getDebugStream() << "[invalid stateID: " << found->second.state->getID() << "] " << "\n"; + m_idStateMap.erase(found); } } } @@ -76,15 +83,27 @@ void ValidPathSearcher::onStateFork(S2EExecutionState *state, const std::vector< getDebugStream() << "onStateFork" << '\n'; const uint32_t forkPC = state->regs()->getPc(); - getDebugStream() << "[forkPC: " << hexval(forkPC) << "] " - << "[stateID: " << hexval(state->getID()) << "] " - << "[new stateID: " << newStates[0]->getID() << "] " - << "[new stateID: " << newStates[1]->getID() << "] " + const uint32_t id0 = newStates[0]->getID(); + const uint32_t id1 = newStates[1]->getID(); + getDebugStream() << "[callerPC: " << hexval(m_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"; - insertToForkStates(m_callerPC, forkPC, newStates[0]); - insertToForkStates(m_callerPC, forkPC, newStates[1]); + + m_forkStates[m_callerPC][forkPC].push_back(id0); + m_forkStates[m_callerPC][forkPC].push_back(id1); + m_idStateMap[id0] = {newStates[0], forkPC, UNVISITED, 0}; + m_idStateMap[id1] = {newStates[1], forkPC, UNVISITED, 0}; m_idStateMap[state->getID()].flag = VALID; - m_searcherActive = true; + // m_searcherActive = true; +// printForkStates(); +// printStateItems(); } void ValidPathSearcher::onTranslateBlockEnd(ExecutionSignal *signal, S2EExecutionState *state, TranslationBlock *tb, @@ -115,6 +134,9 @@ void ValidPathSearcher::onARMFunctionReturn(S2EExecutionState *state, uint32_t p << "\n"; m_curState = state; m_returnPC = pcReturn; + getDebugStream() << "[caller pc: " << hexval(m_functionCalRetMap[pcReturn]) << "] " + << "[return pc: " << hexval(pcReturn) << "] " + << "\n"; if (!m_searcherActive) { return; @@ -123,26 +145,11 @@ void ValidPathSearcher::onARMFunctionReturn(S2EExecutionState *state, uint32_t p // m_selfSwitch = true; if (m_selfSwitch) { - getDebugStream() << "[states' size " << s2e()->getExecutor()->getStatesCount() << "] " - << "\n"; - - if (g_s2e_state) { - S2EExecutionState *nextState = s2e()->getExecutor()->selectNextState(g_s2e_state); - if (nextState) { - g_s2e_state = nextState; - - } else { - // Do not reschedule the timer anymore - return; - } - } - getDebugStream() << "[states' size " << s2e()->getExecutor()->getStatesCount() << "] " - << "\n"; - - // s2e()->getExecutor()->selectSearcherState(m_curState) - // s2e()->getExecutor()->selectNextState(m_curState); - // s2e()->getExecutor()->suspendState(m_curState); - // s2e()->getExecutor()->setCpuExitRequest(); + // getDebugStream() << "[states' size " << s2e()->getExecutor()->getStatesCount() << "] " + // << "\n"; + env->current_tb = nullptr; + s2e()->getExecutor()->validPathSearcherStateSwitchCallback(s2e()->getExecutor()); + s2e()->getExecutor()->setCpuExitRequest(); } } @@ -157,21 +164,6 @@ void ValidPathSearcher::initConnection() { onARMFunctionConn->onARMFunctionReturnEvent.connect(sigc::mem_fun(*this, &ValidPathSearcher::onARMFunctionReturn)); } -bool ValidPathSearcher::insertToForkStates(const uint32_t callerPC, const uint32_t forkPC, S2EExecutionState *state) { - const auto &foundSameCallerPC = m_forkStateItems.find(callerPC); - if (foundSameCallerPC != m_forkStateItems.end()) { - const auto &foundSameForkPC = foundSameCallerPC->second.find(forkPC); - if (foundSameForkPC != foundSameCallerPC->second.end()) { - if (foundSameForkPC->second.size() >= 2) { - return false; - } - } - } - m_forkStateItems[callerPC][forkPC].push_back(state); - m_idStateMap[state->getID()] = {state, forkPC, UNVISITED, 0}; - return true; -} - bool ValidPathSearcher::selectSelfSwitchedState() { const uint32_t callerPC = m_functionCalRetMap[m_returnPC]; const uint32_t forkPC = m_idStateMap[m_curState->getID()].forkPC; @@ -180,21 +172,21 @@ bool ValidPathSearcher::selectSelfSwitchedState() { << "[forkPC: " << hexval(forkPC) << "] " << "\n"; - for (auto &it : m_forkStateItems[callerPC][forkPC]) { - const int id = it->getID(); - if (m_curState->getID() != id && m_idStateMap[id].flag != INVALID) { - if (m_idStateMap[id].switchCnt >= MAX_SWITCH_CNT) { - m_idStateMap[id].flag = INVALID; - continue; - } - m_idStateMap[id].switchCnt++; - m_idStateMap[id].flag = VALID; - m_curState = m_idStateMap[id].state; - getDebugStream() << "[new self-switched StateID: " << m_curState->getID() << "] " - << "\n"; - return true; - } - } +// for (auto &it : m_forkStates[callerPC][forkPC]) { +// const int id = it->getID(); +// if (m_curState->getID() != id && m_idStateMap[id].flag != INVALID) { +// if (m_idStateMap[id].switchCnt >= MAX_SWITCH_CNT) { +// m_idStateMap[id].flag = INVALID; +// continue; +// } +// m_idStateMap[id].switchCnt++; +// m_idStateMap[id].flag = VALID; +// m_curState = m_idStateMap[id].state; +// getDebugStream() << "[new self-switched StateID: " << m_curState->getID() << "] " +// << "\n"; +// return true; +// } +// } getDebugStream() << "no option for self switch" << "\n"; @@ -236,5 +228,34 @@ bool ValidPathSearcher::selectValidState() { return false; } +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 << "] " + << "\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 << "] " + << "[switchCnt: " << it.second.switchCnt << "] " + << "\n"; + } +} + } // namespace plugins } // namespace s2e diff --git a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h index 2309f310..b953791e 100644 --- a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h @@ -62,16 +62,18 @@ class ValidPathSearcher : public Plugin, public klee::Searcher { bool m_selfSwitch; bool m_searcherActive; - std::map>> m_forkStateItems; + std::map>> m_forkStates; std::map m_idStateMap; std::map m_functionCalRetMap; void initConnection(); - bool insertToForkStates(const uint32_t callerPC, const uint32_t forkPC, S2EExecutionState *state); bool selectSelfSwitchedState(); bool selectUnvisitedState(); bool selectValidState(); + void printForkStates(); + void printStateItems(); + // callbacks void onStateFork(S2EExecutionState *state, const std::vector &newStates, const std::vector> &newConditions); From 3834df0217104944f45608aa8203db684d5302a4 Mon Sep 17 00:00:00 2001 From: hwk2077 Date: Thu, 26 Oct 2023 15:30:03 +0000 Subject: [PATCH 15/15] fix: switch by `yield` --- .../Plugins/Searchers/ValidPathSearcher.cpp | 325 ++++++++++++------ .../s2e/Plugins/Searchers/ValidPathSearcher.h | 25 +- 2 files changed, 247 insertions(+), 103 deletions(-) diff --git a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp index 8c1ac8cf..041299f4 100644 --- a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.cpp @@ -17,6 +17,74 @@ 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(); @@ -29,21 +97,32 @@ 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; - selectSelfSwitchedState(); - return *m_curState; - } - if (selectUnvisitedState()) { + if (m_isSelfSwitchedState) { + if (!selectLastState()) { + m_lstStateId = tmpId; + } + return *m_curState; + } + if (!selectCousinState()) { + m_lstStateId = tmpId; + return *m_curState; + } return *m_curState; } - if (selectValidState()) { + if (selectUnvisitedState() || selectValidState()) { return *m_curState; } - getDebugStream() << "no option" << "\n"; + m_lstStateId = tmpId; return *m_curState; } @@ -51,9 +130,11 @@ void ValidPathSearcher::update(klee::ExecutionState *current, const klee::StateS 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) { @@ -68,89 +149,99 @@ void ValidPathSearcher::update(klee::ExecutionState *current, const klee::StateS } bool ValidPathSearcher::empty() { - // for (const auto &it : m_idStateMap) { - // if (it.second.flag == UNVISITED || it.second.flag == VALID) { - // getDebugStream() << "empty" - // << "\n"; - // return false; - // } - // } return false; } void ValidPathSearcher::onStateFork(S2EExecutionState *state, const std::vector &newStates, const std::vector> &newConditions) { - getDebugStream() << "onStateFork" << '\n'; - + 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(); - getDebugStream() << "[callerPC: " << hexval(m_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"; - - m_forkStates[m_callerPC][forkPC].push_back(id0); - m_forkStates[m_callerPC][forkPC].push_back(id1); - m_idStateMap[id0] = {newStates[0], forkPC, UNVISITED, 0}; - m_idStateMap[id1] = {newStates[1], forkPC, UNVISITED, 0}; - m_idStateMap[state->getID()].flag = VALID; - // m_searcherActive = true; -// printForkStates(); -// printStateItems(); + 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() << "onTranslateBlockEnd" << '\n'; - // - m_tbNum++; - // getDebugStream() << "[the number of blocks: " << m_tbNum << "]" - // << "\n"; + 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() << "onARMFunctionCall" - << "\n"; - m_callerPC = pcCaller; + 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() << "[caller pc: " << hexval(pcCaller) << "] " - << "[return pc: " << hexval(pcReturn) << "] " - << "[pc and context hash: " << hexval(pcCtxHashVal) << "] " - << "\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() << "onARMFunctionReturn" - << "\n"; + getDebugStream(state) << "onARMFunctionReturn" + << "\n"; + DECLARE_PLUGINSTATE(ValidPathSearcherState, state); + plgState->setStateReturnPC(pcReturn); m_curState = state; - m_returnPC = pcReturn; - getDebugStream() << "[caller pc: " << hexval(m_functionCalRetMap[pcReturn]) << "] " - << "[return pc: " << hexval(pcReturn) << "] " - << "\n"; + const uint32_t callerPC = m_functionCalRetMap[pcReturn]; + getDebugStream(state) << "[caller pc: " << hexval(callerPC) << "] " + << "[return pc: " << hexval(pcReturn) << "] " + << "\n"; if (!m_searcherActive) { + plgState->popCallStack(); return; } - // m_selfSwitch = true; - - if (m_selfSwitch) { - // getDebugStream() << "[states' size " << s2e()->getExecutor()->getStatesCount() << "] " - // << "\n"; - env->current_tb = nullptr; - s2e()->getExecutor()->validPathSearcherStateSwitchCallback(s2e()->getExecutor()); - s2e()->getExecutor()->setCpuExitRequest(); + 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() { @@ -164,44 +255,65 @@ void ValidPathSearcher::initConnection() { onARMFunctionConn->onARMFunctionReturnEvent.connect(sigc::mem_fun(*this, &ValidPathSearcher::onARMFunctionReturn)); } -bool ValidPathSearcher::selectSelfSwitchedState() { - const uint32_t callerPC = m_functionCalRetMap[m_returnPC]; - const uint32_t forkPC = m_idStateMap[m_curState->getID()].forkPC; - getDebugStream() << "self switch " - << "[callerPC: " << hexval(callerPC) << "] " - << "[forkPC: " << hexval(forkPC) << "] " +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; +} -// for (auto &it : m_forkStates[callerPC][forkPC]) { -// const int id = it->getID(); -// if (m_curState->getID() != id && m_idStateMap[id].flag != INVALID) { -// if (m_idStateMap[id].switchCnt >= MAX_SWITCH_CNT) { -// m_idStateMap[id].flag = INVALID; -// continue; -// } -// m_idStateMap[id].switchCnt++; -// m_idStateMap[id].flag = VALID; -// m_curState = m_idStateMap[id].state; -// getDebugStream() << "[new self-switched StateID: " << m_curState->getID() << "] " -// << "\n"; -// return true; -// } -// } - - getDebugStream() << "no option for self switch" +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 (it->second.state->getID() != m_curState->getID() && it->second.flag == UNVISITED) { - if (it->second.switchCnt >= MAX_SWITCH_CNT) { - it->second.flag = INVALID; - continue; - } - it->second.switchCnt++; + 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"; @@ -212,13 +324,14 @@ bool ValidPathSearcher::selectUnvisitedState() { } 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) { - if (it->second.switchCnt >= MAX_SWITCH_CNT) { - it->second.flag = INVALID; - continue; - } - it->second.switchCnt++; + m_switchCnt[it->second.callerPC][it->second.forkPC]++; m_curState = it->second.state; getDebugStream() << "[new selected valid stateID: " << m_curState->getID() << "] " << "\n"; @@ -228,6 +341,26 @@ bool ValidPathSearcher::selectValidState() { 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"; @@ -238,7 +371,8 @@ void ValidPathSearcher::printForkStates() { getDebugStream() << "\t[forkPC: " << hexval(it2.first) << "] " << "\n"; for (const auto &it3 : it2.second) { - getDebugStream() << "\t\t[stateID: " << it3 << "] " + getDebugStream() << "\t\t[stateID: " << it3.id1 << ", " << it3.id2 << "] " + << "[call stack level: " << it3.callStkLvl << "] " << "\n"; } } @@ -252,7 +386,6 @@ void ValidPathSearcher::printStateItems() { getDebugStream() << "[stateID: " << it.second.state->getID() << "] " << "[forkPC: " << hexval(it.second.forkPC) << "] " << "[flag: " << it.second.flag << "] " - << "[switchCnt: " << it.second.switchCnt << "] " << "\n"; } } diff --git a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h index b953791e..6c259478 100644 --- a/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h +++ b/libs2eplugins/src/s2e/Plugins/Searchers/ValidPathSearcher.h @@ -33,13 +33,21 @@ using PerifSize = uint32_t; struct StateItem { S2EExecutionState *state; + uint32_t callerPC; uint32_t forkPC; uint32_t flag; - uint32_t switchCnt; + uint64_t tbNum; +}; + +struct ForkStateInfo { + uint32_t id1; + uint32_t id2; + uint32_t callStkLvl; }; enum StatePhase { UNVISITED, INVALID, VALID }; -const int MAX_SWITCH_CNT = 20; +const int MAX_SWITCH_CNT = 10; +const int SELF_SWITCH_CALL_STACK_LVL = 2; class ValidPathSearcher : public Plugin, public klee::Searcher { S2E_PLUGIN @@ -55,22 +63,25 @@ class ValidPathSearcher : public Plugin, public klee::Searcher { sigc::connection m_onTranslateBlockEndConn; ARMFunctionMonitor *onARMFunctionConn; - uint32_t m_tbNum; - uint32_t m_callerPC; - uint32_t m_returnPC; + uint32_t m_lstStateId; S2EExecutionState *m_curState; bool m_selfSwitch; + bool m_isSelfSwitchedState; bool m_searcherActive; - std::map>> m_forkStates; + std::map>> m_forkStates; + std::map> m_switchCnt; std::map m_idStateMap; std::map m_functionCalRetMap; void initConnection(); - bool selectSelfSwitchedState(); + bool selectCousinState(); + bool selectLastState(); bool selectUnvisitedState(); bool selectValidState(); + void triggerSelfSwitch(); + void printForkStates(); void printStateItems();