@@ -353,7 +353,7 @@ class PacRetAnalysis
353
353
public:
354
354
std::vector<MCInstReference>
355
355
getLastClobberingInsts (const MCInst Ret, BinaryFunction &BF,
356
- const BitVector & UsedDirtyRegs) const {
356
+ const ArrayRef<MCPhysReg> UsedDirtyRegs) const {
357
357
if (RegsToTrackInstsFor.empty ())
358
358
return {};
359
359
auto MaybeState = getStateAt (Ret);
@@ -362,7 +362,7 @@ class PacRetAnalysis
362
362
const State &S = *MaybeState;
363
363
// Due to aliasing registers, multiple registers may have been tracked.
364
364
std::set<const MCInst *> LastWritingInsts;
365
- for (MCPhysReg TrackedReg : UsedDirtyRegs. set_bits () ) {
365
+ for (MCPhysReg TrackedReg : UsedDirtyRegs) {
366
366
for (const MCInst *Inst : lastWritingInsts (S, TrackedReg))
367
367
LastWritingInsts.insert (Inst);
368
368
}
@@ -376,57 +376,81 @@ class PacRetAnalysis
376
376
}
377
377
};
378
378
379
+ static std::shared_ptr<Report> tryCheckReturn (const BinaryContext &BC,
380
+ const MCInstReference &Inst,
381
+ const State &S) {
382
+ static const GadgetKind RetKind (" non-protected ret found" );
383
+ if (!BC.MIB ->isReturn (Inst))
384
+ return nullptr ;
385
+
386
+ ErrorOr<MCPhysReg> MaybeRetReg = BC.MIB ->getRegUsedAsRetDest (Inst);
387
+ if (MaybeRetReg.getError ()) {
388
+ return std::make_shared<GenericReport>(
389
+ Inst, " Warning: pac-ret analysis could not analyze this return "
390
+ " instruction" );
391
+ }
392
+ MCPhysReg RetReg = *MaybeRetReg;
393
+ LLVM_DEBUG ({
394
+ traceInst (BC, " Found RET inst" , Inst);
395
+ traceReg (BC, " RetReg" , RetReg);
396
+ traceReg (BC, " Authenticated reg" , BC.MIB ->getAuthenticatedReg (Inst));
397
+ });
398
+ if (BC.MIB ->isAuthenticationOfReg (Inst, RetReg))
399
+ return nullptr ;
400
+ BitVector UsedDirtyRegs = S.NonAutClobRegs ;
401
+ LLVM_DEBUG ({ traceRegMask (BC, " NonAutClobRegs at Ret" , UsedDirtyRegs); });
402
+ UsedDirtyRegs &= BC.MIB ->getAliases (RetReg, /* OnlySmaller=*/ true );
403
+ LLVM_DEBUG ({ traceRegMask (BC, " Intersection with RetReg" , UsedDirtyRegs); });
404
+ if (!UsedDirtyRegs.any ())
405
+ return nullptr ;
406
+
407
+ return std::make_shared<GadgetReport>(RetKind, Inst, UsedDirtyRegs);
408
+ }
409
+
379
410
FunctionAnalysisResult
380
- Analysis::computeDfState (PacRetAnalysis &PRA, BinaryFunction &BF,
411
+ Analysis::computeDfState (BinaryFunction &BF,
381
412
MCPlusBuilder::AllocatorIdTy AllocatorId) {
413
+ FunctionAnalysisResult Result;
414
+
415
+ PacRetAnalysis PRA (BF, AllocatorId, {});
382
416
PRA.run ();
383
417
LLVM_DEBUG ({
384
418
dbgs () << " After PacRetAnalysis:\n " ;
385
419
BF.dump ();
386
420
});
387
421
388
- FunctionAnalysisResult Result;
389
- // Now scan the CFG for non-authenticating return instructions that use an
390
- // overwritten, non-authenticated register as return address.
391
422
BinaryContext &BC = BF.getBinaryContext ();
392
423
for (BinaryBasicBlock &BB : BF) {
393
- for (int64_t I = BB.size () - 1 ; I >= 0 ; --I) {
394
- MCInst &Inst = BB.getInstructionAtIndex (I);
395
- if (BC.MIB ->isReturn (Inst)) {
396
- ErrorOr<MCPhysReg> MaybeRetReg = BC.MIB ->getRegUsedAsRetDest (Inst);
397
- if (MaybeRetReg.getError ()) {
398
- Result.Diagnostics .push_back (std::make_shared<GenericReport>(
399
- MCInstInBBReference (&BB, I),
400
- " Warning: pac-ret analysis could not analyze this return "
401
- " instruction" ));
402
- continue ;
403
- }
404
- MCPhysReg RetReg = *MaybeRetReg;
405
- LLVM_DEBUG ({
406
- traceInst (BC, " Found RET inst" , Inst);
407
- traceReg (BC, " RetReg" , RetReg);
408
- traceReg (BC, " Authenticated reg" , BC.MIB ->getAuthenticatedReg (Inst));
409
- });
410
- if (BC.MIB ->isAuthenticationOfReg (Inst, RetReg))
411
- break ;
412
- BitVector UsedDirtyRegs = PRA.getStateAt (Inst)->NonAutClobRegs ;
413
- LLVM_DEBUG (
414
- { traceRegMask (BC, " NonAutClobRegs at Ret" , UsedDirtyRegs); });
415
- UsedDirtyRegs &= BC.MIB ->getAliases (RetReg, /* OnlySmaller=*/ true );
416
- LLVM_DEBUG (
417
- { traceRegMask (BC, " Intersection with RetReg" , UsedDirtyRegs); });
418
- if (UsedDirtyRegs.any ()) {
419
- static const GadgetKind RetKind (" non-protected ret found" );
420
- // This return instruction needs to be reported
421
- Result.Diagnostics .push_back (std::make_shared<GadgetReport>(
422
- RetKind, MCInstInBBReference (&BB, I),
423
- PRA.getLastClobberingInsts (Inst, BF, UsedDirtyRegs)));
424
- for (MCPhysReg RetRegWithGadget : UsedDirtyRegs.set_bits ())
425
- Result.RegistersAffected .insert (RetRegWithGadget);
426
- }
427
- }
424
+ for (int64_t I = 0 , E = BB.size (); I < E; ++I) {
425
+ MCInstReference Inst (&BB, I);
426
+ const State &S = *PRA.getStateAt (Inst);
427
+
428
+ if (auto Report = tryCheckReturn (BC, Inst, S))
429
+ Result.Diagnostics .push_back (Report);
428
430
}
429
431
}
432
+
433
+ if (Result.Diagnostics .empty ())
434
+ return Result;
435
+
436
+ // Redo the analysis, but now also track which instructions last wrote
437
+ // to any of the registers in RetRegsWithGadgets, so that better
438
+ // diagnostics can be produced.
439
+
440
+ SmallSet<MCPhysReg, 4 > RegsToTrack;
441
+ for (auto Report : Result.Diagnostics )
442
+ for (MCPhysReg Reg : Report->getAffectedRegisters ())
443
+ RegsToTrack.insert (Reg);
444
+
445
+ std::vector<MCPhysReg> RegsToTrackVec (RegsToTrack.begin (), RegsToTrack.end ());
446
+
447
+ PacRetAnalysis PRWIA (BF, AllocatorId, RegsToTrackVec);
448
+ PRWIA.run ();
449
+ for (auto Report : Result.Diagnostics ) {
450
+ Report->setOverwritingInstrs (PRWIA.getLastClobberingInsts (
451
+ Report->Location , BF, Report->getAffectedRegisters ()));
452
+ }
453
+
430
454
return Result;
431
455
}
432
456
@@ -438,27 +462,19 @@ void Analysis::runOnFunction(BinaryFunction &BF,
438
462
BF.dump ();
439
463
});
440
464
441
- if (BF.hasCFG ()) {
442
- PacRetAnalysis PRA (BF, AllocatorId, {});
443
- FunctionAnalysisResult FAR = computeDfState (PRA, BF, AllocatorId);
444
- if (!FAR.RegistersAffected .empty ()) {
445
- // Redo the analysis, but now also track which instructions last wrote
446
- // to any of the registers in RetRegsWithGadgets, so that better
447
- // diagnostics can be produced.
448
- std::vector<MCPhysReg> RegsToTrack;
449
- for (MCPhysReg R : FAR.RegistersAffected )
450
- RegsToTrack.push_back (R);
451
- PacRetAnalysis PRWIA (BF, AllocatorId, RegsToTrack);
452
- FAR = computeDfState (PRWIA, BF, AllocatorId);
453
- }
465
+ if (!BF.hasCFG ())
466
+ return ;
454
467
455
- // `runOnFunction` is typically getting called from multiple threads in
456
- // parallel. Therefore, use a lock to avoid data races when storing the
457
- // result of the analysis in the `AnalysisResults` map.
458
- {
459
- std::lock_guard<std::mutex> Lock (AnalysisResultsMutex);
460
- AnalysisResults[&BF] = FAR;
461
- }
468
+ FunctionAnalysisResult FAR = computeDfState (BF, AllocatorId);
469
+ if (FAR.Diagnostics .empty ())
470
+ return ;
471
+
472
+ // `runOnFunction` is typically getting called from multiple threads in
473
+ // parallel. Therefore, use a lock to avoid data races when storing the
474
+ // result of the analysis in the `AnalysisResults` map.
475
+ {
476
+ std::lock_guard<std::mutex> Lock (AnalysisResultsMutex);
477
+ AnalysisResults[&BF] = FAR;
462
478
}
463
479
}
464
480
0 commit comments