From cf0f5d4fa7710ac9e3530f48ea49ee879c980ca9 Mon Sep 17 00:00:00 2001 From: clc5q <clc5q@git.zephyr-software.com> Date: Thu, 10 Aug 2017 02:03:24 +0000 Subject: [PATCH] Trace fptrs back to constant operands, emit COMPLETE xref annotations if all traces lead to constants. Former-commit-id: 29251dbd5a2fffa953d7477cf782e8f0426406bf --- include/base/SMPFunction.h | 4 +-- src/base/SMPFunction.cpp | 64 +++++++++++++++++++++++++++++++------- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/include/base/SMPFunction.h b/include/base/SMPFunction.h index 6554d10e..98f8e528 100644 --- a/include/base/SMPFunction.h +++ b/include/base/SMPFunction.h @@ -913,7 +913,7 @@ private: void SplitAndSaveRelationalExpr(bool PositiveIncrement, std::size_t LoopNumPlusOne, std::size_t MemWidth, STARSExpression *RangeExpr); // Split relational RangeExpr into upper and lower bonds exprs and save them and their width void TraceInArgPointers(void); // helper for TraceIncomingArgs(), focused on CODEPTR and POINTER types void RemoveLocalRefs(STARSDefUseSet &RefSet); // Remove non-global SSA names from RefSet. - bool FindShadowingPoint2(const ShadowPoint CriticalOp, const bool TracingMemWrite, ShadowSet &ShadowAddrSet, bool &MemUnsafe, ShadowSet &NewCriticalOps); // Trace CriticalOp via copies back to ShadowOp, return false if no shadowing possible + bool FindShadowingPoint2(const ShadowPoint CriticalOp, const bool TracingMemWrite, ShadowSet &ShadowAddrSet, bool &MemUnsafe, ShadowSet &NewCriticalOps, bool &NonConstSourceFound, std::set<STARS_uval_t> &ConstValues); // Trace CriticalOp via copies back to ShadowOp, return false if no shadowing possible bool AnalyzeMemWriteSafety(void); // Try to find safe indirect memory writes void UpdateLoopFollowBlockNum(int HeaderBlockNum, int FollowBlockNum); int FindFollowBlockNum(SMPBasicBlock *CurrBlock, bool StartAtLastInst = false); // Based on control flow structure of CurrBlock, find Ada follow block num; -1 if no structure besides fall-through @@ -962,7 +962,7 @@ private: void EmitReturnTargetAnnotations(void); // Emit Indirect Branch Target destinations for return instructions in this func. void EmitFuncPtrShadowingAnnotations(FILE *InfoAnnotFile); // Emit annotations for func ptr shadowing defense bool IsAlreadyShadowed(const ShadowPoint &CriticalOp); // Is CriticalOp already represented in AlreadyShadowed set? - void EmitShadowingHelper(FILE *InfoAnnotFile, SMPInstr *CurrInst, bool FuncPtr); // common code for different cases in shadowing func ptr, critical args + void EmitShadowingHelper(FILE *InfoAnnotFile, SMPInstr *CurrInst, bool FuncPtr, STARS_ea_t CallAddr); // common code for different cases in shadowing func ptr, critical args void EmitFuncPtrShadowingAnnotations2(FILE *InfoAnnotFile); // Emit annotations for func ptr shadowing defense void EmitArgShadowingAnnotations(FILE *InfoAnnotFile); // Emit annotations for critical argument shadowing defense bool MDFindReturnTypes(void); // Fill ReturnRegTypes[] diff --git a/src/base/SMPFunction.cpp b/src/base/SMPFunction.cpp index df3b7ecb..ba8d70e4 100644 --- a/src/base/SMPFunction.cpp +++ b/src/base/SMPFunction.cpp @@ -13386,16 +13386,25 @@ bool SMPFunction::IsAlreadyShadowed(const ShadowPoint &CriticalOp) { // Trace CriticalOp via copies back to ShadowAddr, return false if no valid means of shadowing it. // Add new CriticalOp shadow-checking points to NewCriticalOps, which will be shadowed with separate indices. // If TracingMemWrite, terminate early when we can prove that CriticalOp was unsafe to use as address reg in memory write. -bool SMPFunction::FindShadowingPoint2(const ShadowPoint CriticalOp, const bool TracingMemWrite, ShadowSet &ShadowAddrSet, bool &MemUnsafe, ShadowSet &NewCriticalOps) { +bool SMPFunction::FindShadowingPoint2(const ShadowPoint CriticalOp, const bool TracingMemWrite, ShadowSet &ShadowAddrSet, bool &MemUnsafe, ShadowSet &NewCriticalOps, bool &NonConstSourceFound, set<STARS_uval_t> &ConstValues) { bool UnsafeChain = false; STARS_ea_t ShadowCheckAddr = CriticalOp.first; STARSOpndTypePtr ShadowCheckUseOp = this->TempShadowList.GetRefNum(CriticalOp.second)->GetOp(); bool DataFlowOpnd = MDIsDataFlowOpnd(ShadowCheckUseOp, this->UsesFramePointer()); + bool Duplicate = this->IsAlreadyShadowed(CriticalOp); if (TracingMemWrite && (!DataFlowOpnd)) return false; - else if ((!DataFlowOpnd) || this->IsAlreadyShadowed(CriticalOp)) { + else if ((!DataFlowOpnd) || Duplicate) { // end the recursion. + bool ImmedOp = ShadowCheckUseOp->IsImmedOp(); + if (!Duplicate && (!ImmedOp)) + NonConstSourceFound = true; + else if (ImmedOp) { + // Save in the set of constant values we traced back to. + pair<set<STARS_uval_t>::iterator, bool> InsertResult = ConstValues.insert(ShadowCheckUseOp->GetImmedValue()); + assert(InsertResult.first != ConstValues.end()); + } return true; // if recursion has not started, ShadowAddrSet will be empty and no annotations will be emitted. } else { @@ -13444,7 +13453,7 @@ bool SMPFunction::FindShadowingPoint2(const ShadowPoint CriticalOp, const bool T } this->TempShadowList.SetRef(UseOp->clone(), PhiIter->GetUseType(PhiIndex), PhiUseSSANum); ShadowPoint PhiUsePoint(CurrShadowAddr, this->TempShadowList.GetSize() - 1); - ValidShadowing = this->FindShadowingPoint2(PhiUsePoint, TracingMemWrite, TempShadowAddrSet, MemUnsafe, NewCriticalOps); + ValidShadowing = this->FindShadowingPoint2(PhiUsePoint, TracingMemWrite, TempShadowAddrSet, MemUnsafe, NewCriticalOps, NonConstSourceFound, ConstValues); if (!ValidShadowing) { break; // we must succeed on all Phi USEs } @@ -13467,6 +13476,7 @@ bool SMPFunction::FindShadowingPoint2(const ShadowPoint CriticalOp, const bool T break; // success if ValidShadowing is true, failure otherwise } else if (STARS_IsSSAMarkerPseudoID(CurrShadowAddr)) { + NonConstSourceFound = true; if (MDIsStackAccessOpnd(UseOp, this->UsesFramePointer())) { // We need to guard against the corner case of a stack location that is // apparently used before it is defined. We cannot emit FPTRSHADOW [RSP-128] @@ -13519,6 +13529,7 @@ bool SMPFunction::FindShadowingPoint2(const ShadowPoint CriticalOp, const bool T } STARSOpndTypePtr NewUseOp = nullptr; if (!CurrInst->IsSimpleCopy(NewUseOp)) { + NonConstSourceFound = true; // We could have something like [rsp+32] := [rsp+32] + 8. // The DEF is the DEF of our CriticalOp, and we cannot trace any farther for this shadowing index. // But the USE of the same operand could be a vulnerable DEF-USE chain that needs its own @@ -13530,6 +13541,7 @@ bool SMPFunction::FindShadowingPoint2(const ShadowPoint CriticalOp, const bool T // due to the non-copy operation, unless it is a stack pointer copy. if (TracingMemWrite) { if (CurrInst->MDIsStackPointerCopy(this->UsesFramePointer())) { + // Stack pointer copy, but not a simple copy. Must be load-effective-address copy. STARSOpndTypePtr LeaMemOp = CurrInst->GetLeaMemUseOp(); if ((nullptr != LeaMemOp) && (!LeaMemOp->IsVoidOp())) { ValidShadowing = MDIsDirectStackAccessOpnd(LeaMemOp, this->UsesFramePointer()); @@ -13606,7 +13618,7 @@ bool SMPFunction::FindShadowingPoint2(const ShadowPoint CriticalOp, const bool T if (!MDIsDirectStackAccessOpnd(NewUseOp, this->UsesFramePointer())) { // The TracingMemWrite case differs from the shadowing case here. // The shadowing case would try (and fail) to trace [eax] while the - // TracingMemWrite case is concerned with tracing eax. If eax is a + // TracingMemWrite case is concerned with tracing eax, not [eax]. If eax is a // loop-invariant value and satisfies the other criteria for memory // write safety, then it should point to the return address only if // it is a copy of an unsafe pointer that was stored to memory. That @@ -13617,6 +13629,7 @@ bool SMPFunction::FindShadowingPoint2(const ShadowPoint CriticalOp, const bool T #define STARS_AGGRESSIVE_MEM_TRACING 1 #if STARS_AGGRESSIVE_MEM_TRACING if (NewUseOp->IsStaticMemOp()) { + NonConstSourceFound = true; ValidShadowing = true; break; } @@ -13671,10 +13684,18 @@ bool SMPFunction::FindShadowingPoint2(const ShadowPoint CriticalOp, const bool T } if (!MDIsDataFlowOpnd(NewUseOp, this->UsesFramePointer())) { // We are finished following the chain. + if (!(NewUseOp->IsImmedOp())) { + NonConstSourceFound = true; + } + else { + // Save in the set of constant values we traced back to. + pair<set<STARS_uval_t>::iterator, bool> InsertResult = ConstValues.insert(ShadowCheckUseOp->GetImmedValue()); + assert(InsertResult.first != ConstValues.end()); + } break; } else { // recurse on NextCriticalOp - ValidShadowing = this->FindShadowingPoint2(NextCriticalOp, TracingMemWrite, ShadowAddrSet, MemUnsafe, NewCriticalOps); + ValidShadowing = this->FindShadowingPoint2(NextCriticalOp, TracingMemWrite, ShadowAddrSet, MemUnsafe, NewCriticalOps, NonConstSourceFound, ConstValues); break; // recursion handled rest of the chain } } // end if not SimpleCopy else ... @@ -13684,6 +13705,9 @@ bool SMPFunction::FindShadowingPoint2(const ShadowPoint CriticalOp, const bool T // Success if we found any shadow points before chain had to terminate in non-mem-write case. // In mem-write case, must be ValidShadowing. bool success = TracingMemWrite ? ValidShadowing : (ValidShadowing || ShadowPointFound); + if (!success) { + NonConstSourceFound = true; + } return success; } // end of SMPFunction::FindShadowingPoint2() @@ -13740,7 +13764,9 @@ bool SMPFunction::AnalyzeMemWriteSafety(void) { ShadowSet ShadowUses; // dummy set of addr+USE pairs to shadow values that will be checked at ShadowCheckAddr ShadowSet NewCriticalOps; // dummy worklist of new shadow USEs and their addresses bool MemUnsafe = false; - bool SafeWrite = this->FindShadowingPoint2(CriticalOp, true, ShadowUses, MemUnsafe, NewCriticalOps); + bool NonConstSourceFound = false; + set<STARS_uval_t> ConstValues; + bool SafeWrite = this->FindShadowingPoint2(CriticalOp, true, ShadowUses, MemUnsafe, NewCriticalOps, NonConstSourceFound, ConstValues); if (SafeWrite) { assert(NewCriticalOps.empty()); // FindShadowingPoint2() should stop before adding to this set STARSDefUseIter DefIter = CurrInst->FindDef(DefOp); @@ -18470,9 +18496,11 @@ int SMPFunction::FindFollowBlockNum(SMPBasicBlock *CurrBlock, bool StartAtLastIn } // end of SMPFunction::FindFollowBlockNum() // common code for different cases in EmitFuncPtrShadowingAnnotations2() -void SMPFunction::EmitShadowingHelper(FILE *InfoAnnotFile, SMPInstr *CurrInst, bool FuncPtr) { +void SMPFunction::EmitShadowingHelper(FILE *InfoAnnotFile, SMPInstr *CurrInst, bool FuncPtr, STARS_ea_t CallAddr) { STARS_ea_t ShadowCheckAddr = CurrInst->GetAddr(); STARS_ea_t OldShadowCheckAddr = STARS_BADADDR; + bool GoodCallAddr = (STARS_BADADDR != CallAddr); + bool InterruptCall = CurrInst->MDIsInterruptCall(); bool ImproveCFG = global_STARS_program->ShouldSTARSMaximizeCFGImprovement(); bool ShadowFuncPtrs = (FuncPtr && global_STARS_program->ShouldSTARSShadowFuncPtrs()); bool ShadowArgs = !FuncPtr; @@ -18494,7 +18522,21 @@ void SMPFunction::EmitShadowingHelper(FILE *InfoAnnotFile, SMPInstr *CurrInst, b bool UnsafeCodePointerChain = false; if (ShadowFuncPtrs) ++STARS_FuncPtrShadowPointsAttempted; - bool ValidShadowing = this->FindShadowingPoint2(CriticalOp, false, ShadowUses, UnsafeCodePointerChain, NewCriticalOps); + bool NonConstSourceFound = false; + set<STARS_uval_t> ConstValues; + bool ValidShadowing = this->FindShadowingPoint2(CriticalOp, false, ShadowUses, UnsafeCodePointerChain, NewCriticalOps, NonConstSourceFound, ConstValues); + if (!NonConstSourceFound && ValidShadowing && ShadowFuncPtrs && GoodCallAddr && (!InterruptCall)) { + SMP_msg("INFO: Only constants found in tracing func ptr at %llx\n", (uint64_t) ShadowCheckAddr); + FILE *XrefsFile = global_STARS_program->GetXrefsFile(); + for (set<STARS_uval_t>::const_iterator ValIter = ConstValues.cbegin(); ValIter != ConstValues.cend(); ++ValIter) { + SMP_fprintf(XrefsFile, "%18llx %6d INSTR XREF IBT FROMIB %18llx INDIRCALL\n", + (uint64_t) (*ValIter), CurrInst->GetSize(), (uint64_t) CallAddr); + } + if (!ConstValues.empty()) { + SMP_fprintf(XrefsFile, "%18llx %6d INSTR XREF FROMIB COMPLETE %6zu INDIRCALL\n", + (uint64_t) CallAddr, CurrInst->GetSize(), ConstValues.size()); + } + } if (ValidShadowing && UnsafeCodePointerChain) { if (ShadowFuncPtrs) ++STARS_FuncPtrShadowPointsSucceeded; @@ -18600,7 +18642,7 @@ void SMPFunction::EmitFuncPtrShadowingAnnotations2(FILE *InfoAnnotFile) { this->TempShadowList.clear(); this->TempShadowList.SetRef(UseIter->GetOp(), UseIter->GetType(), UseIter->GetSSANum()); - this->EmitShadowingHelper(InfoAnnotFile, CurrInst, true); + this->EmitShadowingHelper(InfoAnnotFile, CurrInst, true, CurrInst->GetAddr()); } // end if INDIR_CALL else if (CALL == CurrInst->GetDataFlowType()) { // Search for case 3: CODEPTR passed as outgoing arg. @@ -18628,7 +18670,7 @@ void SMPFunction::EmitFuncPtrShadowingAnnotations2(FILE *InfoAnnotFile) { assert(UseIter != CurrInst->GetLastUse()); this->TempShadowList.clear(); this->TempShadowList.SetRef(ArgOp, UseIter->GetType(), UseIter->GetSSANum()); - this->EmitShadowingHelper(InfoAnnotFile, CurrInst, true); + this->EmitShadowingHelper(InfoAnnotFile, CurrInst, true, STARS_BADADDR); } } // end if CODEPTR ArgIter } // end if INDIR_CALL elsif CALL elsif Case3 arg pass @@ -18696,7 +18738,7 @@ void SMPFunction::EmitArgShadowingAnnotations(FILE *InfoAnnotFile) { assert(UseIter != CurrInst->GetLastUse()); this->TempShadowList.clear(); this->TempShadowList.SetRef(ArgOp, UseIter->GetType(), UseIter->GetSSANum()); - this->EmitShadowingHelper(InfoAnnotFile, CurrInst, false); + this->EmitShadowingHelper(InfoAnnotFile, CurrInst, false, STARS_BADADDR); } } } -- GitLab