1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-24 03:33:20 +01:00
llvm-mirror/unittests/tools/llvm-cfi-verify/FileAnalysis.cpp
Joel Galenson 9249622410 [cfi-verify] Support AArch64.
This patch adds support for AArch64 to cfi-verify.

This required three changes to cfi-verify.  First, it generalizes checking if an instruction is a trap by adding a new isTrap flag to TableGen (and defining it for x86 and AArch64).  Second, the code that ensures that the operand register is not clobbered between the CFI check and the indirect call needs to allow a single dereference (in x86 this happens as part of the jump instruction).  Third, we needed to ensure that return instructions are not counted as indirect branches.  Technically, returns are indirect branches and can be covered by CFI, but LLVM's forward-edge CFI does not protect them, and x86 does not consider them, so we keep that behavior.

In addition, we had to improve AArch64's code to evaluate the branch target of a MCInst to handle calls where the destination is not the first operand (which it often is not).

Differential Revision: https://reviews.llvm.org/D48836

llvm-svn: 337007
2018-07-13 15:19:33 +00:00

1074 lines
40 KiB
C++

//===- llvm/unittests/tools/llvm-cfi-verify/FileAnalysis.cpp --------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../tools/llvm-cfi-verify/lib/FileAnalysis.h"
#include "../tools/llvm-cfi-verify/lib/GraphBuilder.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdlib>
using Instr = ::llvm::cfi_verify::FileAnalysis::Instr;
using ::testing::Eq;
using ::testing::Field;
namespace llvm {
namespace cfi_verify {
namespace {
class ELFTestFileAnalysis : public FileAnalysis {
public:
ELFTestFileAnalysis(StringRef Trip)
: FileAnalysis(Triple(Trip), SubtargetFeatures()) {}
// Expose this method publicly for testing.
void parseSectionContents(ArrayRef<uint8_t> SectionBytes,
uint64_t SectionAddress) {
FileAnalysis::parseSectionContents(SectionBytes, SectionAddress);
}
Error initialiseDisassemblyMembers() {
return FileAnalysis::initialiseDisassemblyMembers();
}
};
class BasicFileAnalysisTest : public ::testing::Test {
public:
BasicFileAnalysisTest(StringRef Trip) : Analysis(Trip) {}
protected:
virtual void SetUp() {
IgnoreDWARFFlag = true;
SuccessfullyInitialised = true;
if (auto Err = Analysis.initialiseDisassemblyMembers()) {
handleAllErrors(std::move(Err), [&](const UnsupportedDisassembly &E) {
SuccessfullyInitialised = false;
outs()
<< "Note: CFIVerifyTests are disabled due to lack of support "
"on this build.\n";
});
}
}
bool SuccessfullyInitialised;
ELFTestFileAnalysis Analysis;
};
class BasicX86FileAnalysisTest : public BasicFileAnalysisTest {
public:
BasicX86FileAnalysisTest() : BasicFileAnalysisTest("x86_64--") {}
};
class BasicAArch64FileAnalysisTest : public BasicFileAnalysisTest {
public:
BasicAArch64FileAnalysisTest() : BasicFileAnalysisTest("aarch64--") {}
};
TEST_F(BasicX86FileAnalysisTest, BasicDisassemblyTraversalTest) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x90, // 0: nop
0xb0, 0x00, // 1: mov $0x0, %al
0x48, 0x89, 0xe5, // 3: mov %rsp, %rbp
0x48, 0x83, 0xec, 0x18, // 6: sub $0x18, %rsp
0x48, 0xbe, 0xc4, 0x07, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, // 10: movabs $0x4007c4, %rsi
0x2f, // 20: (bad)
0x41, 0x0e, // 21: rex.B (bad)
0x62, 0x72, 0x65, 0x61, 0x6b, // 23: (bad) {%k1}
},
0xDEADBEEF);
EXPECT_EQ(nullptr, Analysis.getInstruction(0x0));
EXPECT_EQ(nullptr, Analysis.getInstruction(0x1000));
// 0xDEADBEEF: nop
const auto *InstrMeta = Analysis.getInstruction(0xDEADBEEF);
EXPECT_NE(nullptr, InstrMeta);
EXPECT_EQ(0xDEADBEEF, InstrMeta->VMAddress);
EXPECT_EQ(1u, InstrMeta->InstructionSize);
EXPECT_TRUE(InstrMeta->Valid);
const auto *NextInstrMeta = Analysis.getNextInstructionSequential(*InstrMeta);
EXPECT_EQ(nullptr, Analysis.getPrevInstructionSequential(*InstrMeta));
const auto *PrevInstrMeta = InstrMeta;
// 0xDEADBEEF + 1: mov $0x0, %al
InstrMeta = Analysis.getInstruction(0xDEADBEEF + 1);
EXPECT_NE(nullptr, InstrMeta);
EXPECT_EQ(NextInstrMeta, InstrMeta);
EXPECT_EQ(0xDEADBEEF + 1, InstrMeta->VMAddress);
EXPECT_EQ(2u, InstrMeta->InstructionSize);
EXPECT_TRUE(InstrMeta->Valid);
NextInstrMeta = Analysis.getNextInstructionSequential(*InstrMeta);
EXPECT_EQ(PrevInstrMeta, Analysis.getPrevInstructionSequential(*InstrMeta));
PrevInstrMeta = InstrMeta;
// 0xDEADBEEF + 3: mov %rsp, %rbp
InstrMeta = Analysis.getInstruction(0xDEADBEEF + 3);
EXPECT_NE(nullptr, InstrMeta);
EXPECT_EQ(NextInstrMeta, InstrMeta);
EXPECT_EQ(0xDEADBEEF + 3, InstrMeta->VMAddress);
EXPECT_EQ(3u, InstrMeta->InstructionSize);
EXPECT_TRUE(InstrMeta->Valid);
NextInstrMeta = Analysis.getNextInstructionSequential(*InstrMeta);
EXPECT_EQ(PrevInstrMeta, Analysis.getPrevInstructionSequential(*InstrMeta));
PrevInstrMeta = InstrMeta;
// 0xDEADBEEF + 6: sub $0x18, %rsp
InstrMeta = Analysis.getInstruction(0xDEADBEEF + 6);
EXPECT_NE(nullptr, InstrMeta);
EXPECT_EQ(NextInstrMeta, InstrMeta);
EXPECT_EQ(0xDEADBEEF + 6, InstrMeta->VMAddress);
EXPECT_EQ(4u, InstrMeta->InstructionSize);
EXPECT_TRUE(InstrMeta->Valid);
NextInstrMeta = Analysis.getNextInstructionSequential(*InstrMeta);
EXPECT_EQ(PrevInstrMeta, Analysis.getPrevInstructionSequential(*InstrMeta));
PrevInstrMeta = InstrMeta;
// 0xDEADBEEF + 10: movabs $0x4007c4, %rsi
InstrMeta = Analysis.getInstruction(0xDEADBEEF + 10);
EXPECT_NE(nullptr, InstrMeta);
EXPECT_EQ(NextInstrMeta, InstrMeta);
EXPECT_EQ(0xDEADBEEF + 10, InstrMeta->VMAddress);
EXPECT_EQ(10u, InstrMeta->InstructionSize);
EXPECT_TRUE(InstrMeta->Valid);
EXPECT_EQ(nullptr, Analysis.getNextInstructionSequential(*InstrMeta));
EXPECT_EQ(PrevInstrMeta, Analysis.getPrevInstructionSequential(*InstrMeta));
PrevInstrMeta = InstrMeta;
// 0xDEADBEEF + 20: (bad)
InstrMeta = Analysis.getInstruction(0xDEADBEEF + 20);
EXPECT_NE(nullptr, InstrMeta);
EXPECT_EQ(0xDEADBEEF + 20, InstrMeta->VMAddress);
EXPECT_EQ(1u, InstrMeta->InstructionSize);
EXPECT_FALSE(InstrMeta->Valid);
EXPECT_EQ(nullptr, Analysis.getNextInstructionSequential(*InstrMeta));
EXPECT_EQ(PrevInstrMeta, Analysis.getPrevInstructionSequential(*InstrMeta));
// 0xDEADBEEF + 21: rex.B (bad)
InstrMeta = Analysis.getInstruction(0xDEADBEEF + 21);
EXPECT_NE(nullptr, InstrMeta);
EXPECT_EQ(0xDEADBEEF + 21, InstrMeta->VMAddress);
EXPECT_EQ(2u, InstrMeta->InstructionSize);
EXPECT_FALSE(InstrMeta->Valid);
EXPECT_EQ(nullptr, Analysis.getNextInstructionSequential(*InstrMeta));
EXPECT_EQ(nullptr, Analysis.getPrevInstructionSequential(*InstrMeta));
// 0xDEADBEEF + 6: (bad) {%k1}
InstrMeta = Analysis.getInstruction(0xDEADBEEF + 23);
EXPECT_NE(nullptr, InstrMeta);
EXPECT_EQ(0xDEADBEEF + 23, InstrMeta->VMAddress);
EXPECT_EQ(5u, InstrMeta->InstructionSize);
EXPECT_FALSE(InstrMeta->Valid);
EXPECT_EQ(nullptr, Analysis.getNextInstructionSequential(*InstrMeta));
EXPECT_EQ(nullptr, Analysis.getPrevInstructionSequential(*InstrMeta));
}
TEST_F(BasicX86FileAnalysisTest, PrevAndNextFromBadInst) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x90, // 0: nop
0x2f, // 1: (bad)
0x90 // 2: nop
},
0xDEADBEEF);
const auto &BadInstrMeta = Analysis.getInstructionOrDie(0xDEADBEEF + 1);
const auto *GoodInstrMeta =
Analysis.getPrevInstructionSequential(BadInstrMeta);
EXPECT_NE(nullptr, GoodInstrMeta);
EXPECT_EQ(0xDEADBEEF, GoodInstrMeta->VMAddress);
EXPECT_EQ(1u, GoodInstrMeta->InstructionSize);
GoodInstrMeta = Analysis.getNextInstructionSequential(BadInstrMeta);
EXPECT_NE(nullptr, GoodInstrMeta);
EXPECT_EQ(0xDEADBEEF + 2, GoodInstrMeta->VMAddress);
EXPECT_EQ(1u, GoodInstrMeta->InstructionSize);
}
TEST_F(BasicX86FileAnalysisTest, CFITrapTest) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x90, // 0: nop
0xb0, 0x00, // 1: mov $0x0, %al
0x48, 0x89, 0xe5, // 3: mov %rsp, %rbp
0x48, 0x83, 0xec, 0x18, // 6: sub $0x18, %rsp
0x48, 0xbe, 0xc4, 0x07, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, // 10: movabs $0x4007c4, %rsi
0x2f, // 20: (bad)
0x41, 0x0e, // 21: rex.B (bad)
0x62, 0x72, 0x65, 0x61, 0x6b, // 23: (bad) {%k1}
0x0f, 0x0b // 28: ud2
},
0xDEADBEEF);
EXPECT_FALSE(Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF)));
EXPECT_FALSE(
Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 3)));
EXPECT_FALSE(
Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 6)));
EXPECT_FALSE(
Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 10)));
EXPECT_FALSE(
Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 20)));
EXPECT_FALSE(
Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 21)));
EXPECT_FALSE(
Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 23)));
EXPECT_TRUE(
Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 28)));
}
TEST_F(BasicX86FileAnalysisTest, FallThroughTest) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x90, // 0: nop
0xb0, 0x00, // 1: mov $0x0, %al
0x2f, // 3: (bad)
0x0f, 0x0b, // 4: ud2
0xff, 0x20, // 6: jmpq *(%rax)
0xeb, 0x00, // 8: jmp +0
0xe8, 0x45, 0xfe, 0xff, 0xff, // 10: callq [some loc]
0xff, 0x10, // 15: callq *(rax)
0x75, 0x00, // 17: jne +0
0xc3, // 19: retq
},
0xDEADBEEF);
EXPECT_TRUE(
Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF)));
EXPECT_TRUE(
Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 1)));
EXPECT_FALSE(
Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 3)));
EXPECT_FALSE(
Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 4)));
EXPECT_FALSE(
Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 6)));
EXPECT_FALSE(
Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 8)));
EXPECT_FALSE(
Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 10)));
EXPECT_FALSE(
Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 15)));
EXPECT_TRUE(
Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 17)));
EXPECT_FALSE(
Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 19)));
}
TEST_F(BasicX86FileAnalysisTest, DefiniteNextInstructionTest) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x90, // 0: nop
0xb0, 0x00, // 1: mov $0x0, %al
0x2f, // 3: (bad)
0x0f, 0x0b, // 4: ud2
0xff, 0x20, // 6: jmpq *(%rax)
0xeb, 0x00, // 8: jmp 10 [+0]
0xeb, 0x05, // 10: jmp 17 [+5]
0xe8, 0x00, 0x00, 0x00, 0x00, // 12: callq 17 [+0]
0xe8, 0x78, 0x56, 0x34, 0x12, // 17: callq 0x1234569f [+0x12345678]
0xe8, 0x04, 0x00, 0x00, 0x00, // 22: callq 31 [+4]
0xff, 0x10, // 27: callq *(rax)
0x75, 0x00, // 29: jne 31 [+0]
0x75, 0xe0, // 31: jne 1 [-32]
0xc3, // 33: retq
0xeb, 0xdd, // 34: jmp 1 [-35]
0xeb, 0xdd, // 36: jmp 3 [-35]
0xeb, 0xdc, // 38: jmp 4 [-36]
},
0xDEADBEEF);
const auto *Current = Analysis.getInstruction(0xDEADBEEF);
const auto *Next = Analysis.getDefiniteNextInstruction(*Current);
EXPECT_NE(nullptr, Next);
EXPECT_EQ(0xDEADBEEF + 1, Next->VMAddress);
Current = Analysis.getInstruction(0xDEADBEEF + 1);
EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
Current = Analysis.getInstruction(0xDEADBEEF + 3);
EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
Current = Analysis.getInstruction(0xDEADBEEF + 4);
EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
Current = Analysis.getInstruction(0xDEADBEEF + 6);
EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
Current = Analysis.getInstruction(0xDEADBEEF + 8);
Next = Analysis.getDefiniteNextInstruction(*Current);
EXPECT_NE(nullptr, Next);
EXPECT_EQ(0xDEADBEEF + 10, Next->VMAddress);
Current = Analysis.getInstruction(0xDEADBEEF + 10);
Next = Analysis.getDefiniteNextInstruction(*Current);
EXPECT_NE(nullptr, Next);
EXPECT_EQ(0xDEADBEEF + 17, Next->VMAddress);
Current = Analysis.getInstruction(0xDEADBEEF + 12);
Next = Analysis.getDefiniteNextInstruction(*Current);
EXPECT_NE(nullptr, Next);
EXPECT_EQ(0xDEADBEEF + 17, Next->VMAddress);
Current = Analysis.getInstruction(0xDEADBEEF + 17);
// Note, definite next instruction address is out of range and should fail.
EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
Next = Analysis.getDefiniteNextInstruction(*Current);
Current = Analysis.getInstruction(0xDEADBEEF + 22);
Next = Analysis.getDefiniteNextInstruction(*Current);
EXPECT_NE(nullptr, Next);
EXPECT_EQ(0xDEADBEEF + 31, Next->VMAddress);
Current = Analysis.getInstruction(0xDEADBEEF + 27);
EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
Current = Analysis.getInstruction(0xDEADBEEF + 29);
EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
Current = Analysis.getInstruction(0xDEADBEEF + 31);
EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
Current = Analysis.getInstruction(0xDEADBEEF + 33);
EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
Current = Analysis.getInstruction(0xDEADBEEF + 34);
Next = Analysis.getDefiniteNextInstruction(*Current);
EXPECT_NE(nullptr, Next);
EXPECT_EQ(0xDEADBEEF + 1, Next->VMAddress);
Current = Analysis.getInstruction(0xDEADBEEF + 36);
EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
Current = Analysis.getInstruction(0xDEADBEEF + 38);
Next = Analysis.getDefiniteNextInstruction(*Current);
EXPECT_NE(nullptr, Next);
EXPECT_EQ(0xDEADBEEF + 4, Next->VMAddress);
}
TEST_F(BasicX86FileAnalysisTest, ControlFlowXRefsTest) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x90, // 0: nop
0xb0, 0x00, // 1: mov $0x0, %al
0x2f, // 3: (bad)
0x0f, 0x0b, // 4: ud2
0xff, 0x20, // 6: jmpq *(%rax)
0xeb, 0x00, // 8: jmp 10 [+0]
0xeb, 0x05, // 10: jmp 17 [+5]
0xe8, 0x00, 0x00, 0x00, 0x00, // 12: callq 17 [+0]
0xe8, 0x78, 0x56, 0x34, 0x12, // 17: callq 0x1234569f [+0x12345678]
0xe8, 0x04, 0x00, 0x00, 0x00, // 22: callq 31 [+4]
0xff, 0x10, // 27: callq *(rax)
0x75, 0x00, // 29: jne 31 [+0]
0x75, 0xe0, // 31: jne 1 [-32]
0xc3, // 33: retq
0xeb, 0xdd, // 34: jmp 1 [-35]
0xeb, 0xdd, // 36: jmp 3 [-35]
0xeb, 0xdc, // 38: jmp 4 [-36]
},
0xDEADBEEF);
const auto *InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF);
std::set<const Instr *> XRefs =
Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
EXPECT_TRUE(XRefs.empty());
InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 1);
XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
EXPECT_THAT(XRefs, UnorderedElementsAre(
Field(&Instr::VMAddress, Eq(0xDEADBEEF)),
Field(&Instr::VMAddress, Eq(0xDEADBEEF + 31)),
Field(&Instr::VMAddress, Eq(0xDEADBEEF + 34))));
InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 3);
XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
EXPECT_THAT(XRefs, UnorderedElementsAre(
Field(&Instr::VMAddress, Eq(0xDEADBEEF + 1)),
Field(&Instr::VMAddress, Eq(0xDEADBEEF + 36))));
InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 4);
XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
EXPECT_THAT(XRefs, UnorderedElementsAre(
Field(&Instr::VMAddress, Eq(0xDEADBEEF + 38))));
InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 6);
EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 8);
XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 10);
XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
EXPECT_THAT(XRefs, UnorderedElementsAre(
Field(&Instr::VMAddress, Eq(0xDEADBEEF + 8))));
InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 12);
XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 17);
XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
EXPECT_THAT(XRefs, UnorderedElementsAre(
Field(&Instr::VMAddress, Eq(0xDEADBEEF + 10)),
Field(&Instr::VMAddress, Eq(0xDEADBEEF + 12))));
InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 22);
XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 27);
XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 29);
XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 31);
XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
EXPECT_THAT(XRefs, UnorderedElementsAre(
Field(&Instr::VMAddress, Eq(0xDEADBEEF + 22)),
Field(&Instr::VMAddress, Eq(0xDEADBEEF + 29))));
InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 33);
XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
EXPECT_THAT(XRefs, UnorderedElementsAre(
Field(&Instr::VMAddress, Eq(0xDEADBEEF + 31))));
InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 34);
XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 36);
XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 38);
XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
}
TEST_F(BasicX86FileAnalysisTest, CFIProtectionInvalidTargets) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x90, // 0: nop
0x0f, 0x0b, // 1: ud2
0x75, 0x00, // 3: jne 5 [+0]
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF);
EXPECT_EQ(CFIProtectionStatus::FAIL_NOT_INDIRECT_CF,
Analysis.validateCFIProtection(Result));
Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 1);
EXPECT_EQ(CFIProtectionStatus::FAIL_NOT_INDIRECT_CF,
Analysis.validateCFIProtection(Result));
Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 3);
EXPECT_EQ(CFIProtectionStatus::FAIL_NOT_INDIRECT_CF,
Analysis.validateCFIProtection(Result));
Result = GraphBuilder::buildFlowGraph(Analysis, 0x12345678);
EXPECT_EQ(CFIProtectionStatus::FAIL_INVALID_INSTRUCTION,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicX86FileAnalysisTest, CFIProtectionBasicFallthroughToUd2) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x75, 0x02, // 0: jne 4 [+2]
0x0f, 0x0b, // 2: ud2
0xff, 0x10, // 4: callq *(%rax)
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 4);
EXPECT_EQ(CFIProtectionStatus::PROTECTED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicX86FileAnalysisTest, CFIProtectionBasicJumpToUd2) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x75, 0x02, // 0: jne 4 [+2]
0xff, 0x10, // 2: callq *(%rax)
0x0f, 0x0b, // 4: ud2
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 2);
EXPECT_EQ(CFIProtectionStatus::PROTECTED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicX86FileAnalysisTest, CFIProtectionDualPathUd2) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x75, 0x03, // 0: jne 5 [+3]
0x90, // 2: nop
0xff, 0x10, // 3: callq *(%rax)
0x0f, 0x0b, // 5: ud2
0x75, 0xf9, // 7: jne 2 [-7]
0x0f, 0x0b, // 9: ud2
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 3);
EXPECT_EQ(CFIProtectionStatus::PROTECTED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicX86FileAnalysisTest, CFIProtectionDualPathSingleUd2) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x75, 0x05, // 0: jne 7 [+5]
0x90, // 2: nop
0xff, 0x10, // 3: callq *(%rax)
0x75, 0xfb, // 5: jne 2 [-5]
0x0f, 0x0b, // 7: ud2
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 3);
EXPECT_EQ(CFIProtectionStatus::PROTECTED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicX86FileAnalysisTest, CFIProtectionDualFailLimitUpwards) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x75, 0x06, // 0: jne 8 [+6]
0x90, // 2: nop
0x90, // 3: nop
0x90, // 4: nop
0x90, // 5: nop
0xff, 0x10, // 6: callq *(%rax)
0x0f, 0x0b, // 8: ud2
},
0xDEADBEEF);
uint64_t PrevSearchLengthForConditionalBranch =
SearchLengthForConditionalBranch;
SearchLengthForConditionalBranch = 2;
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 6);
EXPECT_EQ(CFIProtectionStatus::FAIL_ORPHANS,
Analysis.validateCFIProtection(Result));
SearchLengthForConditionalBranch = PrevSearchLengthForConditionalBranch;
}
TEST_F(BasicX86FileAnalysisTest, CFIProtectionDualFailLimitDownwards) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x75, 0x02, // 0: jne 4 [+2]
0xff, 0x10, // 2: callq *(%rax)
0x90, // 4: nop
0x90, // 5: nop
0x90, // 6: nop
0x90, // 7: nop
0x0f, 0x0b, // 8: ud2
},
0xDEADBEEF);
uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;
SearchLengthForUndef = 2;
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 2);
EXPECT_EQ(CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH,
Analysis.validateCFIProtection(Result));
SearchLengthForUndef = PrevSearchLengthForUndef;
}
TEST_F(BasicX86FileAnalysisTest, CFIProtectionGoodAndBadPaths) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0xeb, 0x02, // 0: jmp 4 [+2]
0x75, 0x02, // 2: jne 6 [+2]
0xff, 0x10, // 4: callq *(%rax)
0x0f, 0x0b, // 6: ud2
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 4);
EXPECT_EQ(CFIProtectionStatus::FAIL_ORPHANS,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicX86FileAnalysisTest, CFIProtectionWithUnconditionalJumpInFallthrough) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x75, 0x04, // 0: jne 6 [+4]
0xeb, 0x00, // 2: jmp 4 [+0]
0xff, 0x10, // 4: callq *(%rax)
0x0f, 0x0b, // 6: ud2
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 4);
EXPECT_EQ(CFIProtectionStatus::PROTECTED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicX86FileAnalysisTest, CFIProtectionComplexExample) {
if (!SuccessfullyInitialised)
return;
// See unittests/GraphBuilder.cpp::BuildFlowGraphComplexExample for this
// graph.
Analysis.parseSectionContents(
{
0x75, 0x12, // 0: jne 20 [+18]
0xeb, 0x03, // 2: jmp 7 [+3]
0x75, 0x10, // 4: jne 22 [+16]
0x90, // 6: nop
0x90, // 7: nop
0x90, // 8: nop
0xff, 0x10, // 9: callq *(%rax)
0xeb, 0xfc, // 11: jmp 9 [-4]
0x75, 0xfa, // 13: jne 9 [-6]
0xe8, 0x78, 0x56, 0x34, 0x12, // 15: callq OUTOFBOUNDS [+0x12345678]
0x90, // 20: nop
0x90, // 21: nop
0x0f, 0x0b, // 22: ud2
},
0xDEADBEEF);
uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;
SearchLengthForUndef = 5;
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 9);
EXPECT_EQ(CFIProtectionStatus::FAIL_ORPHANS,
Analysis.validateCFIProtection(Result));
SearchLengthForUndef = PrevSearchLengthForUndef;
}
TEST_F(BasicX86FileAnalysisTest, UndefSearchLengthOneTest) {
Analysis.parseSectionContents(
{
0x77, 0x0d, // 0x688118: ja 0x688127 [+12]
0x48, 0x89, 0xdf, // 0x68811a: mov %rbx, %rdi
0xff, 0xd0, // 0x68811d: callq *%rax
0x48, 0x89, 0xdf, // 0x68811f: mov %rbx, %rdi
0xe8, 0x09, 0x00, 0x00, 0x00, // 0x688122: callq 0x688130
0x0f, 0x0b, // 0x688127: ud2
},
0x688118);
uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;
SearchLengthForUndef = 1;
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0x68811d);
EXPECT_EQ(CFIProtectionStatus::PROTECTED,
Analysis.validateCFIProtection(Result));
SearchLengthForUndef = PrevSearchLengthForUndef;
}
TEST_F(BasicX86FileAnalysisTest, UndefSearchLengthOneTestFarAway) {
Analysis.parseSectionContents(
{
0x74, 0x73, // 0x7759eb: je 0x775a60
0xe9, 0x1c, 0x04, 0x00, 0x00, 0x00, // 0x7759ed: jmpq 0x775e0e
},
0x7759eb);
Analysis.parseSectionContents(
{
0x0f, 0x85, 0xb2, 0x03, 0x00, 0x00, // 0x775a56: jne 0x775e0e
0x48, 0x83, 0xc3, 0xf4, // 0x775a5c: add $0xfffffffffffffff4,%rbx
0x48, 0x8b, 0x7c, 0x24, 0x10, // 0x775a60: mov 0x10(%rsp),%rdi
0x48, 0x89, 0xde, // 0x775a65: mov %rbx,%rsi
0xff, 0xd1, // 0x775a68: callq *%rcx
},
0x775a56);
Analysis.parseSectionContents(
{
0x0f, 0x0b, // 0x775e0e: ud2
},
0x775e0e);
uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;
SearchLengthForUndef = 1;
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0x775a68);
EXPECT_EQ(CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH,
Analysis.validateCFIProtection(Result));
SearchLengthForUndef = 2;
Result = GraphBuilder::buildFlowGraph(Analysis, 0x775a68);
EXPECT_EQ(CFIProtectionStatus::PROTECTED,
Analysis.validateCFIProtection(Result));
SearchLengthForUndef = 3;
Result = GraphBuilder::buildFlowGraph(Analysis, 0x775a68);
EXPECT_EQ(CFIProtectionStatus::PROTECTED,
Analysis.validateCFIProtection(Result));
SearchLengthForUndef = PrevSearchLengthForUndef;
}
TEST_F(BasicX86FileAnalysisTest, CFIProtectionClobberSinglePathExplicit) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x75, 0x02, // 0: jne 4 [+2]
0x0f, 0x0b, // 2: ud2
0x48, 0x05, 0x00, 0x00, 0x00, 0x00, // 4: add $0x0, %rax
0xff, 0x10, // 10: callq *(%rax)
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 10);
EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicX86FileAnalysisTest, CFIProtectionClobberSinglePathExplicit2) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x75, 0x02, // 0: jne 4 [+2]
0x0f, 0x0b, // 2: ud2
0x48, 0x83, 0xc0, 0x00, // 4: add $0x0, %rax
0xff, 0x10, // 8: callq *(%rax)
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 8);
EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicX86FileAnalysisTest, CFIProtectionClobberSinglePathImplicit) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x75, 0x02, // 0: jne 4 [+2]
0x0f, 0x0b, // 2: ud2
0x05, 0x00, 0x00, 0x00, 0x00, // 4: add $0x0, %eax
0xff, 0x10, // 9: callq *(%rax)
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 9);
EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicX86FileAnalysisTest, CFIProtectionClobberDualPathImplicit) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x75, 0x04, // 0: jne 6 [+4]
0x0f, 0x31, // 2: rdtsc (note: affects eax)
0xff, 0x10, // 4: callq *(%rax)
0x0f, 0x0b, // 6: ud2
0x75, 0xf9, // 8: jne 2 [-7]
0x0f, 0x0b, // 10: ud2
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 4);
EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicAArch64FileAnalysisTest, AArch64BasicUnprotected) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x00, 0x01, 0x3f, 0xd6, // 0: blr x8
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF);
EXPECT_EQ(CFIProtectionStatus::FAIL_ORPHANS,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicAArch64FileAnalysisTest, AArch64BasicProtected) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
0x00, 0x01, 0x3f, 0xd6, // 8: blr x8
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 8);
EXPECT_EQ(CFIProtectionStatus::PROTECTED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberBasic) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
0x08, 0x05, 0x00, 0x91, // 8: add x8, x8, #1
0x00, 0x01, 0x3f, 0xd6, // 12: blr x8
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 12);
EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberOneLoad) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
0x21, 0x09, 0x40, 0xf9, // 8: ldr x1, [x9,#16]
0x20, 0x00, 0x1f, 0xd6, // 12: br x1
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 12);
EXPECT_EQ(CFIProtectionStatus::PROTECTED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberLoadAddGood) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
0x21, 0x04, 0x00, 0x91, // 8: add x1, x1, #1
0x21, 0x09, 0x40, 0xf9, // 12: ldr x1, [x9,#16]
0x20, 0x00, 0x1f, 0xd6, // 16: br x1
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 16);
EXPECT_EQ(CFIProtectionStatus::PROTECTED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberLoadAddBad) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
0x21, 0x09, 0x40, 0xf9, // 8: ldr x1, [x9,#16]
0x21, 0x04, 0x00, 0x91, // 12: add x1, x1, #1
0x20, 0x00, 0x1f, 0xd6, // 16: br x1
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 16);
EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberLoadAddBad2) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
0x29, 0x04, 0x00, 0x91, // 16: add x9, x1, #1
0x21, 0x09, 0x40, 0xf9, // 12: ldr x1, [x9,#16]
0x20, 0x00, 0x1f, 0xd6, // 16: br x1
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 16);
EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberTwoLoads) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
0x21, 0x09, 0x40, 0xf9, // 8: ldr x1, [x9,#16]
0x21, 0x08, 0x40, 0xf9, // 12: ldr x1, [x1,#16]
0x20, 0x00, 0x1f, 0xd6, // 16: br x1
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 16);
EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberUnrelatedSecondLoad) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
0x21, 0x09, 0x40, 0xf9, // 8: ldr x1, [x9,#16]
0x21, 0x09, 0x40, 0xf9, // 12: ldr x1, [x9,#16]
0x20, 0x00, 0x1f, 0xd6, // 16: br x1
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 16);
EXPECT_EQ(CFIProtectionStatus::PROTECTED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberUnrelatedLoads) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
0x22, 0x09, 0x40, 0xf9, // 8: ldr x2, [x9,#16]
0x22, 0x08, 0x40, 0xf9, // 12: ldr x2, [x1,#16]
0x20, 0x00, 0x1f, 0xd6, // 16: br x1
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 16);
EXPECT_EQ(CFIProtectionStatus::PROTECTED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicAArch64FileAnalysisTest, AArch64GoodAndBadPaths) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0x03, 0x00, 0x00, 0x14, // 0: b 12
0x49, 0x00, 0x00, 0x54, // 4: b.ls 8
0x20, 0x00, 0x20, 0xd4, // 8: brk #0x1
0x20, 0x00, 0x1f, 0xd6, // 12: br x1
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 12);
EXPECT_EQ(CFIProtectionStatus::FAIL_ORPHANS,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicAArch64FileAnalysisTest, AArch64TwoPaths) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0xc9, 0x00, 0x00, 0x54, // 0: b.ls 24
0x21, 0x08, 0x40, 0xf9, // 4: ldr x1, [x1,#16]
0x03, 0x00, 0x00, 0x14, // 8: b 12
0x69, 0x00, 0x00, 0x54, // 12: b.ls 12
0x21, 0x08, 0x40, 0xf9, // 16: ldr x1, [x1,#16]
0x20, 0x00, 0x1f, 0xd6, // 20: br x1
0x20, 0x00, 0x20, 0xd4, // 24: brk #0x1
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 20);
EXPECT_EQ(CFIProtectionStatus::PROTECTED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicAArch64FileAnalysisTest, AArch64TwoPathsBadLoad1) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0xe9, 0x00, 0x00, 0x54, // 0: b.ls 28
0x21, 0x08, 0x40, 0xf9, // 4: ldr x1, [x1,#16]
0x21, 0x08, 0x40, 0xf9, // 8: ldr x1, [x1,#16]
0x03, 0x00, 0x00, 0x14, // 12: b 12
0x69, 0x00, 0x00, 0x54, // 16: b.ls 12
0x21, 0x08, 0x40, 0xf9, // 20: ldr x1, [x1,#16]
0x20, 0x00, 0x1f, 0xd6, // 24: br x1
0x20, 0x00, 0x20, 0xd4, // 28: brk #0x1
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 24);
EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
Analysis.validateCFIProtection(Result));
}
TEST_F(BasicAArch64FileAnalysisTest, AArch64TwoPathsBadLoad2) {
if (!SuccessfullyInitialised)
return;
Analysis.parseSectionContents(
{
0xe9, 0x00, 0x00, 0x54, // 0: b.ls 28
0x21, 0x08, 0x40, 0xf9, // 4: ldr x1, [x1,#16]
0x03, 0x00, 0x00, 0x14, // 8: b 12
0x89, 0x00, 0x00, 0x54, // 12: b.ls 16
0x21, 0x08, 0x40, 0xf9, // 16: ldr x1, [x1,#16]
0x21, 0x08, 0x40, 0xf9, // 20: ldr x1, [x1,#16]
0x20, 0x00, 0x1f, 0xd6, // 24: br x1
0x20, 0x00, 0x20, 0xd4, // 28: brk #0x1
},
0xDEADBEEF);
GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 24);
EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
Analysis.validateCFIProtection(Result));
}
} // anonymous namespace
} // end namespace cfi_verify
} // end namespace llvm
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
llvm::cl::ParseCommandLineOptions(argc, argv);
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
llvm::InitializeAllDisassemblers();
return RUN_ALL_TESTS();
}