Recipe 插件 – 2. PovGenerationPolicy 根据 【S2E插件分析】Recipe插件 -- 1.Recipe ,最后是 PovGenerationPolicy 插件注册了 Recipe 的 onPovReady 事件。
1 m_recipe->onPovReady.connect (sigc::bind (sigc::mem_fun (*this , &PovGenerationPolicy::onPovReadyHandler), false ));
这里主要研究它干了什么。
1 2 3 4 5 6 void PovGenerationPolicy::onPovReadyHandler ( S2EExecutionState *state, const PovOptions &opt, const std::string &recipeName, bool isCrash ) ;
PovOptions 的定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 struct PovOptions { PovType m_type; uint64_t m_faultAddress; uint64_t m_ipMask; uint64_t m_regMask; uint64_t m_regNum; size_t m_bytesBeforeSecret; ExprList m_extraConstraints; VariableRemapping m_remapping; PovOptions () { m_type = POV_GENERAL; m_faultAddress = 0 ; m_ipMask = 0 ; m_regMask = 0 ; m_regNum = 0 ; m_bytesBeforeSecret = 0 ; } };
在 Recipe.cpp 发出 onPovReady 时,是这样设置 PovOptions 变量的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 PovOptions opt; opt.m_type = settings.type; opt.m_faultAddress = state->regs ()->getPc (); opt.m_extraConstraints = l_recipeConditions.constraints; opt.m_remapping = l_recipeConditions.remappings; if (settings.type == PovType::POV_TYPE1) { opt.m_ipMask = settings.ipMask; opt.m_regMask = settings.regMask; opt.m_regNum = settings.gp->reg (); } else if (settings.type == PovType::POV_TYPE2) { opt.m_bytesBeforeSecret = settings.skip; }
下面是 onPovReadyHandler()
的具体内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 getInfoStream (state) << "Generating PoV type " << opt.m_type << " at " << hexval (opt.m_faultAddress) << " from recipe '" << recipeName << "'\n" ; UniquePovKey uniquePovKey = std::make_tuple (opt.m_faultAddress, opt.m_type, recipeName); if (m_uniquePovMap[uniquePovKey] >= m_maxPovCount) { getDebugStream (state) << "PoV limit reached\n" ; return ; } m_uniquePovMap[uniquePovKey]++; std::string prefix; if (recipeName.length ()) { std::stringstream povFilenameSS; povFilenameSS << "recipe-" << recipeName; prefix = povFilenameSS.str (); } else if (isCrash) { prefix = "crash" ; } std::vector<std::string> filePaths; if (!m_povGenerator->generatePoV (state, opt, prefix, filePaths)) { getWarningsStream (state) << "Failed to generate PoV\n" ; return ; } onPovReady.emit (state, opt, recipeName, filePaths, isCrash ? CRASH : POV);
这里又弹出了 onPovReady 事件,不过这个事件只在 CGCInterface 这个插件里使用,是用来在 CGC 里提交 flag 的,就不看了。
所以,其实约束求解的地方还是在 PovGenerator 插件中。
这里还有一个我感兴趣的地方是,调用 Recipe 生成了 Pov 之后,对应的状态会被杀死。而杀死的操作是在这个插件(PovGenerationPolicy) 里完成的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 void PovGenerationPolicy::onSymbolicAddress (S2EExecutionState *state, ref<Expr> virtualAddress, uint64_t concreteAddress, bool &concretize, CorePlugin::symbolicAddressReason reason) { if (!m_process->isTrackedPc (state, state->regs ()->getPc (), true )) { return ; } if (reason != CorePlugin::symbolicAddressReason::PC) { return ; } for (const auto &it : m_uniquePovMap) { auto pc = std::get <0 >(it.first); if (state->regs ()->getPc () == pc) { s2e ()->getExecutor ()->terminateState (*state, "Killing state because that PC has already generated a PoV" ); } } }
根据注释中的描述,符号化的 pc 会导致 S2E fork,由于已经生成了 pov,那么就不需要再继续运行这个 state 了,因此把生成了 pov 的 state 都杀死。
这里我有两个疑问:
通过 onSymbolicAddress 事件来杀死 state,但在 Recipe.cpp 中,是通过 onSymbolicAddress 事件来触发 tryRecipes,如何保证 Recipe.cpp 注册的回调函数优先于 PovGenerationPolicy 呢?
如果我希望修改 Recipe,让约束附加之后不终止,而是继续运行,在合适的时机附加下一次约束,那么,符号化的 pc 是否会 fork 从而影响我的操作?我应该如何处理?