llvm.org GIT mirror llvm / 46254ad
Add FileVerifier::isCFIProtected(). Add a CFI protection check that is implemented by building a graph and inspecting the output to deduce if the indirect CF instruction is CFI protected. Also added the output of this instruction to printIndirectInstructions(). Reviewers: vlad.tsyrklevich Subscribers: llvm-commits, kcc, pcc, mgorny Differential Revision: https://reviews.llvm.org/D38428 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@316610 91177308-0d34-0410-b5e6-96231b3b80d8 Mitch Phillips 1 year, 9 months ago
4 changed file(s) with 209 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
77 //===----------------------------------------------------------------------===//
88
99 #include "FileAnalysis.h"
10 #include "GraphBuilder.h"
1011
1112 #include "llvm/BinaryFormat/ELF.h"
1213 #include "llvm/MC/MCAsmInfo.h"
7576 const SubtargetFeatures &Features)
7677 : ObjectTriple(ObjectTriple), Features(Features) {}
7778
79 bool FileAnalysis::isIndirectInstructionCFIProtected(uint64_t Address) const {
80 const Instr *InstrMetaPtr = getInstruction(Address);
81 if (!InstrMetaPtr)
82 return false;
83
84 const auto &InstrDesc = MII->get(InstrMetaPtr->Instruction.getOpcode());
85
86 if (!InstrDesc.mayAffectControlFlow(InstrMetaPtr->Instruction, *RegisterInfo))
87 return false;
88
89 if (!usesRegisterOperand(*InstrMetaPtr))
90 return false;
91
92 auto Flows = GraphBuilder::buildFlowGraph(*this, Address);
93
94 if (!Flows.OrphanedNodes.empty())
95 return false;
96
97 for (const auto &BranchNode : Flows.ConditionalBranchNodes) {
98 if (!BranchNode.CFIProtection)
99 return false;
100 }
101
102 return true;
103 }
104
78105 const Instr *
79106 FileAnalysis::getPrevInstructionSequential(const Instr &InstrMeta) const {
80107 std::map::const_iterator KV =
225252 if (!ObjectTarget)
226253 return make_error(
227254 (Twine("Couldn't find target \"") + ObjectTriple.getTriple() +
228 "\", failed with error: " + ErrorString).str());
255 "\", failed with error: " + ErrorString)
256 .str());
229257
230258 RegisterInfo.reset(ObjectTarget->createMCRegInfo(TripleName));
231259 if (!RegisterInfo)
6464 FileAnalysis() = delete;
6565 FileAnalysis(const FileAnalysis &) = delete;
6666 FileAnalysis(FileAnalysis &&Other) = default;
67
68 // Check whether the provided instruction is CFI protected in this file.
69 // Returns false if this instruction doesn't exist in this file, if it's not
70 // an indirect control flow instruction, or isn't CFI protected. Returns true
71 // otherwise.
72 bool isIndirectInstructionCFIProtected(uint64_t Address) const;
6773
6874 // Returns the instruction at the provided address. Returns nullptr if there
6975 // is no instruction at the provided address.
4242 << " ";
4343 InstrMeta.Instruction.print(outs());
4444 outs() << "\n";
45 outs() << " Protected? "
46 << Verifier.isIndirectInstructionCFIProtected(Address) << "\n";
4547 }
4648 }
4749
77 //===----------------------------------------------------------------------===//
88
99 #include "../tools/llvm-cfi-verify/lib/FileAnalysis.h"
10 #include "../tools/llvm-cfi-verify/lib/GraphBuilder.h"
1011 #include "gmock/gmock.h"
1112 #include "gtest/gtest.h"
1213
480481 EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
481482 }
482483
484 TEST_F(BasicFileAnalysisTest, CFIProtectionInvalidTargets) {
485 if (!SuccessfullyInitialised)
486 return;
487 Analysis.parseSectionContents(
488 {
489 0x90, // 0: nop
490 0x0f, 0x0b, // 1: ud2
491 0x75, 0x00, // 3: jne 5 [+0]
492 },
493 0xDEADBEEF);
494 EXPECT_FALSE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF));
495 EXPECT_FALSE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 1));
496 EXPECT_FALSE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 3));
497 EXPECT_FALSE(Analysis.isIndirectInstructionCFIProtected(0xDEADC0DE));
498 }
499
500 TEST_F(BasicFileAnalysisTest, CFIProtectionBasicFallthroughToUd2) {
501 if (!SuccessfullyInitialised)
502 return;
503 Analysis.parseSectionContents(
504 {
505 0x75, 0x02, // 0: jne 4 [+2]
506 0x0f, 0x0b, // 2: ud2
507 0xff, 0x10, // 4: callq *(%rax)
508 },
509 0xDEADBEEF);
510 EXPECT_TRUE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 4));
511 }
512
513 TEST_F(BasicFileAnalysisTest, CFIProtectionBasicJumpToUd2) {
514 if (!SuccessfullyInitialised)
515 return;
516 Analysis.parseSectionContents(
517 {
518 0x75, 0x02, // 0: jne 4 [+2]
519 0xff, 0x10, // 2: callq *(%rax)
520 0x0f, 0x0b, // 4: ud2
521 },
522 0xDEADBEEF);
523 EXPECT_TRUE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 2));
524 }
525
526 TEST_F(BasicFileAnalysisTest, CFIProtectionDualPathUd2) {
527 if (!SuccessfullyInitialised)
528 return;
529 Analysis.parseSectionContents(
530 {
531 0x75, 0x03, // 0: jne 5 [+3]
532 0x90, // 2: nop
533 0xff, 0x10, // 3: callq *(%rax)
534 0x0f, 0x0b, // 5: ud2
535 0x75, 0xf9, // 7: jne 2 [-7]
536 0x0f, 0x0b, // 9: ud2
537 },
538 0xDEADBEEF);
539 EXPECT_TRUE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 3));
540 }
541
542 TEST_F(BasicFileAnalysisTest, CFIProtectionDualPathSingleUd2) {
543 if (!SuccessfullyInitialised)
544 return;
545 Analysis.parseSectionContents(
546 {
547 0x75, 0x05, // 0: jne 7 [+5]
548 0x90, // 2: nop
549 0xff, 0x10, // 3: callq *(%rax)
550 0x75, 0xfb, // 5: jne 2 [-5]
551 0x0f, 0x0b, // 7: ud2
552 },
553 0xDEADBEEF);
554 EXPECT_TRUE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 3));
555 }
556
557 TEST_F(BasicFileAnalysisTest, CFIProtectionDualFailLimitUpwards) {
558 if (!SuccessfullyInitialised)
559 return;
560 Analysis.parseSectionContents(
561 {
562 0x75, 0x06, // 0: jne 8 [+6]
563 0x90, // 2: nop
564 0x90, // 3: nop
565 0x90, // 4: nop
566 0x90, // 5: nop
567 0xff, 0x10, // 6: callq *(%rax)
568 0x0f, 0x0b, // 8: ud2
569 },
570 0xDEADBEEF);
571 uint64_t PrevSearchLengthForConditionalBranch =
572 SearchLengthForConditionalBranch;
573 SearchLengthForConditionalBranch = 2;
574
575 EXPECT_FALSE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 6));
576
577 SearchLengthForConditionalBranch = PrevSearchLengthForConditionalBranch;
578 }
579
580 TEST_F(BasicFileAnalysisTest, CFIProtectionDualFailLimitDownwards) {
581 if (!SuccessfullyInitialised)
582 return;
583 Analysis.parseSectionContents(
584 {
585 0x75, 0x02, // 0: jne 4 [+2]
586 0xff, 0x10, // 2: callq *(%rax)
587 0x90, // 4: nop
588 0x90, // 5: nop
589 0x90, // 6: nop
590 0x90, // 7: nop
591 0x0f, 0x0b, // 8: ud2
592 },
593 0xDEADBEEF);
594 uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;
595 SearchLengthForUndef = 2;
596
597 EXPECT_FALSE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 2));
598
599 SearchLengthForUndef = PrevSearchLengthForUndef;
600 }
601
602 TEST_F(BasicFileAnalysisTest, CFIProtectionGoodAndBadPaths) {
603 if (!SuccessfullyInitialised)
604 return;
605 Analysis.parseSectionContents(
606 {
607 0xeb, 0x02, // 0: jmp 4 [+2]
608 0x75, 0x02, // 2: jne 6 [+2]
609 0xff, 0x10, // 4: callq *(%rax)
610 0x0f, 0x0b, // 6: ud2
611 },
612 0xDEADBEEF);
613 EXPECT_FALSE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 4));
614 }
615
616 TEST_F(BasicFileAnalysisTest, CFIProtectionWithUnconditionalJumpInFallthrough) {
617 if (!SuccessfullyInitialised)
618 return;
619 Analysis.parseSectionContents(
620 {
621 0x75, 0x04, // 0: jne 6 [+4]
622 0xeb, 0x00, // 2: jmp 4 [+0]
623 0xff, 0x10, // 4: callq *(%rax)
624 0x0f, 0x0b, // 6: ud2
625 },
626 0xDEADBEEF);
627 EXPECT_TRUE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 4));
628 }
629
630 TEST_F(BasicFileAnalysisTest, CFIProtectionComplexExample) {
631 if (!SuccessfullyInitialised)
632 return;
633 // See unittests/GraphBuilder.cpp::BuildFlowGraphComplexExample for this
634 // graph.
635 Analysis.parseSectionContents(
636 {
637 0x75, 0x12, // 0: jne 20 [+18]
638 0xeb, 0x03, // 2: jmp 7 [+3]
639 0x75, 0x10, // 4: jne 22 [+16]
640 0x90, // 6: nop
641 0x90, // 7: nop
642 0x90, // 8: nop
643 0xff, 0x10, // 9: callq *(%rax)
644 0xeb, 0xfc, // 11: jmp 9 [-4]
645 0x75, 0xfa, // 13: jne 9 [-6]
646 0xe8, 0x78, 0x56, 0x34, 0x12, // 15: callq OUTOFBOUNDS [+0x12345678]
647 0x90, // 20: nop
648 0x90, // 21: nop
649 0x0f, 0x0b, // 22: ud2
650 },
651 0xDEADBEEF);
652 EXPECT_FALSE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 9));
653 }
654
483655 } // anonymous namespace
484656 } // end namespace cfi_verify
485657 } // end namespace llvm