@@ -701,8 +701,9 @@ class DataflowSrcSafetyAnalysis
701701// 
702702//  Then, a function can be split into a number of disjoint contiguous sequences
703703//  of instructions without labels in between. These sequences can be processed
704- //  the same way basic blocks are processed by data-flow analysis, assuming
705- //  pessimistically that all registers are unsafe at the start of each sequence.
704+ //  the same way basic blocks are processed by data-flow analysis, with the same
705+ //  pessimistic estimation of the initial state at the start of each sequence
706+ //  (except the first instruction of the function).
706707class  CFGUnawareSrcSafetyAnalysis  : public  SrcSafetyAnalysis  {
707708  BinaryFunction &BF;
708709  MCPlusBuilder::AllocatorIdTy AllocId;
@@ -713,12 +714,6 @@ class CFGUnawareSrcSafetyAnalysis : public SrcSafetyAnalysis {
713714      BC.MIB ->removeAnnotation (I.second , StateAnnotationIndex);
714715  }
715716
716-   // / Creates a state with all registers marked unsafe (not to be confused
717-   // / with empty state).
718-   SrcState createUnsafeState () const  {
719-     return  SrcState (NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters ());
720-   }
721- 
722717public: 
723718  CFGUnawareSrcSafetyAnalysis (BinaryFunction &BF,
724719                              MCPlusBuilder::AllocatorIdTy AllocId,
@@ -729,6 +724,7 @@ class CFGUnawareSrcSafetyAnalysis : public SrcSafetyAnalysis {
729724  }
730725
731726  void  run () override  {
727+     const  SrcState DefaultState = computePessimisticState (BF);
732728    SrcState S = createEntryState ();
733729    for  (auto  &I : BF.instrs ()) {
734730      MCInst &Inst = I.second ;
@@ -743,7 +739,7 @@ class CFGUnawareSrcSafetyAnalysis : public SrcSafetyAnalysis {
743739        LLVM_DEBUG ({
744740          traceInst (BC, " Due to label, resetting the state before"  , Inst);
745741        });
746-         S = createUnsafeState () ;
742+         S = DefaultState ;
747743      }
748744
749745      //  Check if we need to remove an old annotation (this is the case if
@@ -1288,6 +1284,83 @@ shouldReportReturnGadget(const BinaryContext &BC, const MCInstReference &Inst,
12881284  return  make_gadget_report (RetKind, Inst, *RetReg);
12891285}
12901286
1287+ // / While BOLT already marks some of the branch instructions as tail calls,
1288+ // / this function tries to improve the coverage by including less obvious cases
1289+ // / when it is possible to do without introducing too many false positives.
1290+ static  bool  shouldAnalyzeTailCallInst (const  BinaryContext &BC,
1291+                                       const  BinaryFunction &BF,
1292+                                       const  MCInstReference &Inst) {
1293+   //  Some BC.MIB->isXYZ(Inst) methods simply delegate to MCInstrDesc::isXYZ()
1294+   //  (such as isBranch at the time of writing this comment), some don't (such
1295+   //  as isCall). For that reason, call MCInstrDesc's methods explicitly when
1296+   //  it is important.
1297+   const  MCInstrDesc &Desc =
1298+       BC.MII ->get (static_cast <const  MCInst &>(Inst).getOpcode ());
1299+   //  Tail call should be a branch (but not necessarily an indirect one).
1300+   if  (!Desc.isBranch ())
1301+     return  false ;
1302+ 
1303+   //  Always analyze the branches already marked as tail calls by BOLT.
1304+   if  (BC.MIB ->isTailCall (Inst))
1305+     return  true ;
1306+ 
1307+   //  Try to also check the branches marked as "UNKNOWN CONTROL FLOW" - the
1308+   //  below is a simplified condition from BinaryContext::printInstruction.
1309+   bool  IsUnknownControlFlow =
1310+       BC.MIB ->isIndirectBranch (Inst) && !BC.MIB ->getJumpTable (Inst);
1311+ 
1312+   if  (BF.hasCFG () && IsUnknownControlFlow)
1313+     return  true ;
1314+ 
1315+   return  false ;
1316+ }
1317+ 
1318+ static  std::optional<PartialReport<MCPhysReg>>
1319+ shouldReportUnsafeTailCall (const  BinaryContext &BC, const  BinaryFunction &BF,
1320+                            const  MCInstReference &Inst, const  SrcState &S) {
1321+   static  const  GadgetKind UntrustedLRKind (
1322+       " untrusted link register found before tail call"  );
1323+ 
1324+   if  (!shouldAnalyzeTailCallInst (BC, BF, Inst))
1325+     return  std::nullopt ;
1326+ 
1327+   //  Not only the set of registers returned by getTrustedLiveInRegs() can be
1328+   //  seen as a reasonable target-independent _approximation_ of "the LR", these
1329+   //  are *exactly* those registers used by SrcSafetyAnalysis to initialize the
1330+   //  set of trusted registers on function entry.
1331+   //  Thus, this function basically checks that the precondition expected to be
1332+   //  imposed by a function call instruction (which is hardcoded into the target-
1333+   //  specific getTrustedLiveInRegs() function) is also respected on tail calls.
1334+   SmallVector<MCPhysReg> RegsToCheck = BC.MIB ->getTrustedLiveInRegs ();
1335+   LLVM_DEBUG ({
1336+     traceInst (BC, " Found tail call inst"  , Inst);
1337+     traceRegMask (BC, " Trusted regs"  , S.TrustedRegs );
1338+   });
1339+ 
1340+   //  In musl on AArch64, the _start function sets LR to zero and calls the next
1341+   //  stage initialization function at the end, something along these lines:
1342+   // 
1343+   //    _start:
1344+   //      mov     x30, #0
1345+   //      ; ... other initialization ...
1346+   //      b       _start_c ; performs "exit" system call at some point
1347+   // 
1348+   //  As this would produce a false positive for every executable linked with
1349+   //  such libc, ignore tail calls performed by ELF entry function.
1350+   if  (BC.StartFunctionAddress  &&
1351+       *BC.StartFunctionAddress  == Inst.getFunction ()->getAddress ()) {
1352+     LLVM_DEBUG ({ dbgs () << "   Skipping tail call in ELF entry function.\n "  ; });
1353+     return  std::nullopt ;
1354+   }
1355+ 
1356+   //  Returns at most one report per instruction - this is probably OK...
1357+   for  (auto  Reg : RegsToCheck)
1358+     if  (!S.TrustedRegs [Reg])
1359+       return  make_gadget_report (UntrustedLRKind, Inst, Reg);
1360+ 
1361+   return  std::nullopt ;
1362+ }
1363+ 
12911364static  std::optional<PartialReport<MCPhysReg>>
12921365shouldReportCallGadget (const  BinaryContext &BC, const  MCInstReference &Inst,
12931366                       const  SrcState &S) {
@@ -1444,6 +1517,9 @@ void FunctionAnalysisContext::findUnsafeUses(
14441517    if  (PacRetGadgetsOnly)
14451518      return ;
14461519
1520+     if  (auto  Report = shouldReportUnsafeTailCall (BC, BF, Inst, S))
1521+       Reports.push_back (*Report);
1522+ 
14471523    if  (auto  Report = shouldReportCallGadget (BC, Inst, S))
14481524      Reports.push_back (*Report);
14491525    if  (auto  Report = shouldReportSigningOracle (BC, Inst, S))
0 commit comments