blob: 05880fcec805d8f6e0af745a977597efacd4cb2c [file] [log] [blame]
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +00001//===- llvm/unittests/tools/llvm-cfi-verify/FileAnalysis.cpp --------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "../tools/llvm-cfi-verify/lib/FileAnalysis.h"
Mitch Phillips5ff01cd2017-10-25 21:21:16 +000011#include "../tools/llvm-cfi-verify/lib/GraphBuilder.h"
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000012#include "gmock/gmock.h"
13#include "gtest/gtest.h"
14
15#include "llvm/BinaryFormat/ELF.h"
16#include "llvm/MC/MCAsmInfo.h"
17#include "llvm/MC/MCContext.h"
18#include "llvm/MC/MCDisassembler/MCDisassembler.h"
19#include "llvm/MC/MCInst.h"
20#include "llvm/MC/MCInstPrinter.h"
21#include "llvm/MC/MCInstrAnalysis.h"
22#include "llvm/MC/MCInstrDesc.h"
23#include "llvm/MC/MCInstrInfo.h"
24#include "llvm/MC/MCObjectFileInfo.h"
25#include "llvm/MC/MCRegisterInfo.h"
26#include "llvm/MC/MCSubtargetInfo.h"
27#include "llvm/Object/Binary.h"
28#include "llvm/Object/COFF.h"
29#include "llvm/Object/ELFObjectFile.h"
30#include "llvm/Object/ObjectFile.h"
31#include "llvm/Support/Casting.h"
32#include "llvm/Support/CommandLine.h"
33#include "llvm/Support/Error.h"
34#include "llvm/Support/MemoryBuffer.h"
35#include "llvm/Support/TargetRegistry.h"
36#include "llvm/Support/TargetSelect.h"
37#include "llvm/Support/raw_ostream.h"
38
39#include <cstdlib>
40
41using Instr = ::llvm::cfi_verify::FileAnalysis::Instr;
42using ::testing::Eq;
Vlad Tsyrklevich0ee26322017-10-11 23:17:29 +000043using ::testing::Field;
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000044
45namespace llvm {
46namespace cfi_verify {
47namespace {
Joel Galenson06e7e572018-07-13 15:19:33 +000048class ELFTestFileAnalysis : public FileAnalysis {
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000049public:
Joel Galenson06e7e572018-07-13 15:19:33 +000050 ELFTestFileAnalysis(StringRef Trip)
51 : FileAnalysis(Triple(Trip), SubtargetFeatures()) {}
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000052
53 // Expose this method publicly for testing.
54 void parseSectionContents(ArrayRef<uint8_t> SectionBytes,
55 uint64_t SectionAddress) {
56 FileAnalysis::parseSectionContents(SectionBytes, SectionAddress);
57 }
58
59 Error initialiseDisassemblyMembers() {
60 return FileAnalysis::initialiseDisassemblyMembers();
61 }
62};
63
64class BasicFileAnalysisTest : public ::testing::Test {
Joel Galenson06e7e572018-07-13 15:19:33 +000065public:
66 BasicFileAnalysisTest(StringRef Trip) : Analysis(Trip) {}
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000067protected:
68 virtual void SetUp() {
Mitch Phillipsc15bdf52017-11-03 20:54:26 +000069 IgnoreDWARFFlag = true;
Mitch Phillipsd9af3832017-10-23 20:54:01 +000070 SuccessfullyInitialised = true;
71 if (auto Err = Analysis.initialiseDisassemblyMembers()) {
72 handleAllErrors(std::move(Err), [&](const UnsupportedDisassembly &E) {
73 SuccessfullyInitialised = false;
74 outs()
Joel Galenson06e7e572018-07-13 15:19:33 +000075 << "Note: CFIVerifyTests are disabled due to lack of support "
Mitch Phillipsd9af3832017-10-23 20:54:01 +000076 "on this build.\n";
77 });
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000078 }
79 }
80
Mitch Phillipsd9af3832017-10-23 20:54:01 +000081 bool SuccessfullyInitialised;
Joel Galenson06e7e572018-07-13 15:19:33 +000082 ELFTestFileAnalysis Analysis;
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000083};
84
Joel Galenson06e7e572018-07-13 15:19:33 +000085class BasicX86FileAnalysisTest : public BasicFileAnalysisTest {
86public:
87 BasicX86FileAnalysisTest() : BasicFileAnalysisTest("x86_64--") {}
88};
89
90class BasicAArch64FileAnalysisTest : public BasicFileAnalysisTest {
91public:
92 BasicAArch64FileAnalysisTest() : BasicFileAnalysisTest("aarch64--") {}
93};
94
95TEST_F(BasicX86FileAnalysisTest, BasicDisassemblyTraversalTest) {
Mitch Phillipsd9af3832017-10-23 20:54:01 +000096 if (!SuccessfullyInitialised)
97 return;
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000098 Analysis.parseSectionContents(
99 {
100 0x90, // 0: nop
101 0xb0, 0x00, // 1: mov $0x0, %al
102 0x48, 0x89, 0xe5, // 3: mov %rsp, %rbp
103 0x48, 0x83, 0xec, 0x18, // 6: sub $0x18, %rsp
104 0x48, 0xbe, 0xc4, 0x07, 0x40,
105 0x00, 0x00, 0x00, 0x00, 0x00, // 10: movabs $0x4007c4, %rsi
106 0x2f, // 20: (bad)
107 0x41, 0x0e, // 21: rex.B (bad)
108 0x62, 0x72, 0x65, 0x61, 0x6b, // 23: (bad) {%k1}
109 },
110 0xDEADBEEF);
111
112 EXPECT_EQ(nullptr, Analysis.getInstruction(0x0));
113 EXPECT_EQ(nullptr, Analysis.getInstruction(0x1000));
114
115 // 0xDEADBEEF: nop
116 const auto *InstrMeta = Analysis.getInstruction(0xDEADBEEF);
117 EXPECT_NE(nullptr, InstrMeta);
118 EXPECT_EQ(0xDEADBEEF, InstrMeta->VMAddress);
119 EXPECT_EQ(1u, InstrMeta->InstructionSize);
120 EXPECT_TRUE(InstrMeta->Valid);
121
122 const auto *NextInstrMeta = Analysis.getNextInstructionSequential(*InstrMeta);
123 EXPECT_EQ(nullptr, Analysis.getPrevInstructionSequential(*InstrMeta));
124 const auto *PrevInstrMeta = InstrMeta;
125
126 // 0xDEADBEEF + 1: mov $0x0, %al
127 InstrMeta = Analysis.getInstruction(0xDEADBEEF + 1);
128 EXPECT_NE(nullptr, InstrMeta);
129 EXPECT_EQ(NextInstrMeta, InstrMeta);
130 EXPECT_EQ(0xDEADBEEF + 1, InstrMeta->VMAddress);
131 EXPECT_EQ(2u, InstrMeta->InstructionSize);
132 EXPECT_TRUE(InstrMeta->Valid);
133
134 NextInstrMeta = Analysis.getNextInstructionSequential(*InstrMeta);
135 EXPECT_EQ(PrevInstrMeta, Analysis.getPrevInstructionSequential(*InstrMeta));
136 PrevInstrMeta = InstrMeta;
137
138 // 0xDEADBEEF + 3: mov %rsp, %rbp
139 InstrMeta = Analysis.getInstruction(0xDEADBEEF + 3);
140 EXPECT_NE(nullptr, InstrMeta);
141 EXPECT_EQ(NextInstrMeta, InstrMeta);
142 EXPECT_EQ(0xDEADBEEF + 3, InstrMeta->VMAddress);
143 EXPECT_EQ(3u, InstrMeta->InstructionSize);
144 EXPECT_TRUE(InstrMeta->Valid);
145
146 NextInstrMeta = Analysis.getNextInstructionSequential(*InstrMeta);
147 EXPECT_EQ(PrevInstrMeta, Analysis.getPrevInstructionSequential(*InstrMeta));
148 PrevInstrMeta = InstrMeta;
149
150 // 0xDEADBEEF + 6: sub $0x18, %rsp
151 InstrMeta = Analysis.getInstruction(0xDEADBEEF + 6);
152 EXPECT_NE(nullptr, InstrMeta);
153 EXPECT_EQ(NextInstrMeta, InstrMeta);
154 EXPECT_EQ(0xDEADBEEF + 6, InstrMeta->VMAddress);
155 EXPECT_EQ(4u, InstrMeta->InstructionSize);
156 EXPECT_TRUE(InstrMeta->Valid);
157
158 NextInstrMeta = Analysis.getNextInstructionSequential(*InstrMeta);
159 EXPECT_EQ(PrevInstrMeta, Analysis.getPrevInstructionSequential(*InstrMeta));
160 PrevInstrMeta = InstrMeta;
161
162 // 0xDEADBEEF + 10: movabs $0x4007c4, %rsi
163 InstrMeta = Analysis.getInstruction(0xDEADBEEF + 10);
164 EXPECT_NE(nullptr, InstrMeta);
165 EXPECT_EQ(NextInstrMeta, InstrMeta);
166 EXPECT_EQ(0xDEADBEEF + 10, InstrMeta->VMAddress);
167 EXPECT_EQ(10u, InstrMeta->InstructionSize);
168 EXPECT_TRUE(InstrMeta->Valid);
169
170 EXPECT_EQ(nullptr, Analysis.getNextInstructionSequential(*InstrMeta));
171 EXPECT_EQ(PrevInstrMeta, Analysis.getPrevInstructionSequential(*InstrMeta));
172 PrevInstrMeta = InstrMeta;
173
174 // 0xDEADBEEF + 20: (bad)
175 InstrMeta = Analysis.getInstruction(0xDEADBEEF + 20);
176 EXPECT_NE(nullptr, InstrMeta);
177 EXPECT_EQ(0xDEADBEEF + 20, InstrMeta->VMAddress);
178 EXPECT_EQ(1u, InstrMeta->InstructionSize);
179 EXPECT_FALSE(InstrMeta->Valid);
180
181 EXPECT_EQ(nullptr, Analysis.getNextInstructionSequential(*InstrMeta));
182 EXPECT_EQ(PrevInstrMeta, Analysis.getPrevInstructionSequential(*InstrMeta));
183
184 // 0xDEADBEEF + 21: rex.B (bad)
185 InstrMeta = Analysis.getInstruction(0xDEADBEEF + 21);
186 EXPECT_NE(nullptr, InstrMeta);
187 EXPECT_EQ(0xDEADBEEF + 21, InstrMeta->VMAddress);
188 EXPECT_EQ(2u, InstrMeta->InstructionSize);
189 EXPECT_FALSE(InstrMeta->Valid);
190
191 EXPECT_EQ(nullptr, Analysis.getNextInstructionSequential(*InstrMeta));
192 EXPECT_EQ(nullptr, Analysis.getPrevInstructionSequential(*InstrMeta));
193
194 // 0xDEADBEEF + 6: (bad) {%k1}
195 InstrMeta = Analysis.getInstruction(0xDEADBEEF + 23);
196 EXPECT_NE(nullptr, InstrMeta);
197 EXPECT_EQ(0xDEADBEEF + 23, InstrMeta->VMAddress);
198 EXPECT_EQ(5u, InstrMeta->InstructionSize);
199 EXPECT_FALSE(InstrMeta->Valid);
200
201 EXPECT_EQ(nullptr, Analysis.getNextInstructionSequential(*InstrMeta));
202 EXPECT_EQ(nullptr, Analysis.getPrevInstructionSequential(*InstrMeta));
203}
204
Joel Galenson06e7e572018-07-13 15:19:33 +0000205TEST_F(BasicX86FileAnalysisTest, PrevAndNextFromBadInst) {
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000206 if (!SuccessfullyInitialised)
207 return;
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000208 Analysis.parseSectionContents(
209 {
210 0x90, // 0: nop
211 0x2f, // 1: (bad)
212 0x90 // 2: nop
213 },
214 0xDEADBEEF);
215 const auto &BadInstrMeta = Analysis.getInstructionOrDie(0xDEADBEEF + 1);
216 const auto *GoodInstrMeta =
217 Analysis.getPrevInstructionSequential(BadInstrMeta);
218 EXPECT_NE(nullptr, GoodInstrMeta);
219 EXPECT_EQ(0xDEADBEEF, GoodInstrMeta->VMAddress);
220 EXPECT_EQ(1u, GoodInstrMeta->InstructionSize);
221
222 GoodInstrMeta = Analysis.getNextInstructionSequential(BadInstrMeta);
223 EXPECT_NE(nullptr, GoodInstrMeta);
224 EXPECT_EQ(0xDEADBEEF + 2, GoodInstrMeta->VMAddress);
225 EXPECT_EQ(1u, GoodInstrMeta->InstructionSize);
226}
227
Joel Galenson06e7e572018-07-13 15:19:33 +0000228TEST_F(BasicX86FileAnalysisTest, CFITrapTest) {
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000229 if (!SuccessfullyInitialised)
230 return;
Vlad Tsyrklevich0ee26322017-10-11 23:17:29 +0000231 Analysis.parseSectionContents(
232 {
233 0x90, // 0: nop
234 0xb0, 0x00, // 1: mov $0x0, %al
235 0x48, 0x89, 0xe5, // 3: mov %rsp, %rbp
236 0x48, 0x83, 0xec, 0x18, // 6: sub $0x18, %rsp
237 0x48, 0xbe, 0xc4, 0x07, 0x40,
238 0x00, 0x00, 0x00, 0x00, 0x00, // 10: movabs $0x4007c4, %rsi
239 0x2f, // 20: (bad)
240 0x41, 0x0e, // 21: rex.B (bad)
241 0x62, 0x72, 0x65, 0x61, 0x6b, // 23: (bad) {%k1}
242 0x0f, 0x0b // 28: ud2
243 },
244 0xDEADBEEF);
245
246 EXPECT_FALSE(Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF)));
247 EXPECT_FALSE(
248 Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 3)));
249 EXPECT_FALSE(
250 Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 6)));
251 EXPECT_FALSE(
252 Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 10)));
253 EXPECT_FALSE(
254 Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 20)));
255 EXPECT_FALSE(
256 Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 21)));
257 EXPECT_FALSE(
258 Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 23)));
259 EXPECT_TRUE(
260 Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 28)));
261}
262
Joel Galenson06e7e572018-07-13 15:19:33 +0000263TEST_F(BasicX86FileAnalysisTest, FallThroughTest) {
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000264 if (!SuccessfullyInitialised)
265 return;
Vlad Tsyrklevich0ee26322017-10-11 23:17:29 +0000266 Analysis.parseSectionContents(
267 {
268 0x90, // 0: nop
269 0xb0, 0x00, // 1: mov $0x0, %al
270 0x2f, // 3: (bad)
271 0x0f, 0x0b, // 4: ud2
272 0xff, 0x20, // 6: jmpq *(%rax)
273 0xeb, 0x00, // 8: jmp +0
274 0xe8, 0x45, 0xfe, 0xff, 0xff, // 10: callq [some loc]
275 0xff, 0x10, // 15: callq *(rax)
276 0x75, 0x00, // 17: jne +0
277 0xc3, // 19: retq
278 },
279 0xDEADBEEF);
280
281 EXPECT_TRUE(
282 Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF)));
283 EXPECT_TRUE(
284 Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 1)));
285 EXPECT_FALSE(
286 Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 3)));
287 EXPECT_FALSE(
288 Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 4)));
289 EXPECT_FALSE(
290 Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 6)));
291 EXPECT_FALSE(
292 Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 8)));
293 EXPECT_FALSE(
294 Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 10)));
295 EXPECT_FALSE(
296 Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 15)));
297 EXPECT_TRUE(
298 Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 17)));
299 EXPECT_FALSE(
300 Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 19)));
301}
302
Joel Galenson06e7e572018-07-13 15:19:33 +0000303TEST_F(BasicX86FileAnalysisTest, DefiniteNextInstructionTest) {
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000304 if (!SuccessfullyInitialised)
305 return;
Vlad Tsyrklevich0ee26322017-10-11 23:17:29 +0000306 Analysis.parseSectionContents(
307 {
308 0x90, // 0: nop
309 0xb0, 0x00, // 1: mov $0x0, %al
310 0x2f, // 3: (bad)
311 0x0f, 0x0b, // 4: ud2
312 0xff, 0x20, // 6: jmpq *(%rax)
313 0xeb, 0x00, // 8: jmp 10 [+0]
314 0xeb, 0x05, // 10: jmp 17 [+5]
315 0xe8, 0x00, 0x00, 0x00, 0x00, // 12: callq 17 [+0]
316 0xe8, 0x78, 0x56, 0x34, 0x12, // 17: callq 0x1234569f [+0x12345678]
317 0xe8, 0x04, 0x00, 0x00, 0x00, // 22: callq 31 [+4]
318 0xff, 0x10, // 27: callq *(rax)
319 0x75, 0x00, // 29: jne 31 [+0]
320 0x75, 0xe0, // 31: jne 1 [-32]
321 0xc3, // 33: retq
322 0xeb, 0xdd, // 34: jmp 1 [-35]
323 0xeb, 0xdd, // 36: jmp 3 [-35]
324 0xeb, 0xdc, // 38: jmp 4 [-36]
325 },
326 0xDEADBEEF);
327
328 const auto *Current = Analysis.getInstruction(0xDEADBEEF);
329 const auto *Next = Analysis.getDefiniteNextInstruction(*Current);
330 EXPECT_NE(nullptr, Next);
331 EXPECT_EQ(0xDEADBEEF + 1, Next->VMAddress);
332
333 Current = Analysis.getInstruction(0xDEADBEEF + 1);
334 EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
335
336 Current = Analysis.getInstruction(0xDEADBEEF + 3);
337 EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
338
339 Current = Analysis.getInstruction(0xDEADBEEF + 4);
340 EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
341
342 Current = Analysis.getInstruction(0xDEADBEEF + 6);
343 EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
344
345 Current = Analysis.getInstruction(0xDEADBEEF + 8);
346 Next = Analysis.getDefiniteNextInstruction(*Current);
347 EXPECT_NE(nullptr, Next);
348 EXPECT_EQ(0xDEADBEEF + 10, Next->VMAddress);
349
350 Current = Analysis.getInstruction(0xDEADBEEF + 10);
351 Next = Analysis.getDefiniteNextInstruction(*Current);
352 EXPECT_NE(nullptr, Next);
353 EXPECT_EQ(0xDEADBEEF + 17, Next->VMAddress);
354
355 Current = Analysis.getInstruction(0xDEADBEEF + 12);
356 Next = Analysis.getDefiniteNextInstruction(*Current);
357 EXPECT_NE(nullptr, Next);
358 EXPECT_EQ(0xDEADBEEF + 17, Next->VMAddress);
359
360 Current = Analysis.getInstruction(0xDEADBEEF + 17);
361 // Note, definite next instruction address is out of range and should fail.
362 EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
363 Next = Analysis.getDefiniteNextInstruction(*Current);
364
365 Current = Analysis.getInstruction(0xDEADBEEF + 22);
366 Next = Analysis.getDefiniteNextInstruction(*Current);
367 EXPECT_NE(nullptr, Next);
368 EXPECT_EQ(0xDEADBEEF + 31, Next->VMAddress);
369
370 Current = Analysis.getInstruction(0xDEADBEEF + 27);
371 EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
372 Current = Analysis.getInstruction(0xDEADBEEF + 29);
373 EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
374 Current = Analysis.getInstruction(0xDEADBEEF + 31);
375 EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
376 Current = Analysis.getInstruction(0xDEADBEEF + 33);
377 EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
378
379 Current = Analysis.getInstruction(0xDEADBEEF + 34);
380 Next = Analysis.getDefiniteNextInstruction(*Current);
381 EXPECT_NE(nullptr, Next);
382 EXPECT_EQ(0xDEADBEEF + 1, Next->VMAddress);
383
384 Current = Analysis.getInstruction(0xDEADBEEF + 36);
385 EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current));
386
387 Current = Analysis.getInstruction(0xDEADBEEF + 38);
388 Next = Analysis.getDefiniteNextInstruction(*Current);
389 EXPECT_NE(nullptr, Next);
390 EXPECT_EQ(0xDEADBEEF + 4, Next->VMAddress);
391}
392
Joel Galenson06e7e572018-07-13 15:19:33 +0000393TEST_F(BasicX86FileAnalysisTest, ControlFlowXRefsTest) {
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000394 if (!SuccessfullyInitialised)
395 return;
Vlad Tsyrklevich0ee26322017-10-11 23:17:29 +0000396 Analysis.parseSectionContents(
397 {
398 0x90, // 0: nop
399 0xb0, 0x00, // 1: mov $0x0, %al
400 0x2f, // 3: (bad)
401 0x0f, 0x0b, // 4: ud2
402 0xff, 0x20, // 6: jmpq *(%rax)
403 0xeb, 0x00, // 8: jmp 10 [+0]
404 0xeb, 0x05, // 10: jmp 17 [+5]
405 0xe8, 0x00, 0x00, 0x00, 0x00, // 12: callq 17 [+0]
406 0xe8, 0x78, 0x56, 0x34, 0x12, // 17: callq 0x1234569f [+0x12345678]
407 0xe8, 0x04, 0x00, 0x00, 0x00, // 22: callq 31 [+4]
408 0xff, 0x10, // 27: callq *(rax)
409 0x75, 0x00, // 29: jne 31 [+0]
410 0x75, 0xe0, // 31: jne 1 [-32]
411 0xc3, // 33: retq
412 0xeb, 0xdd, // 34: jmp 1 [-35]
413 0xeb, 0xdd, // 36: jmp 3 [-35]
414 0xeb, 0xdc, // 38: jmp 4 [-36]
415 },
416 0xDEADBEEF);
417 const auto *InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF);
418 std::set<const Instr *> XRefs =
419 Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
420 EXPECT_TRUE(XRefs.empty());
421
422 InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 1);
423 XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
424 EXPECT_THAT(XRefs, UnorderedElementsAre(
425 Field(&Instr::VMAddress, Eq(0xDEADBEEF)),
426 Field(&Instr::VMAddress, Eq(0xDEADBEEF + 31)),
427 Field(&Instr::VMAddress, Eq(0xDEADBEEF + 34))));
428
429 InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 3);
430 XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
431 EXPECT_THAT(XRefs, UnorderedElementsAre(
432 Field(&Instr::VMAddress, Eq(0xDEADBEEF + 1)),
433 Field(&Instr::VMAddress, Eq(0xDEADBEEF + 36))));
434
435 InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 4);
436 XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
437 EXPECT_THAT(XRefs, UnorderedElementsAre(
438 Field(&Instr::VMAddress, Eq(0xDEADBEEF + 38))));
439
440 InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 6);
441 EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
442
443 InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 8);
444 XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
445 EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
446
447 InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 10);
448 XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
449 EXPECT_THAT(XRefs, UnorderedElementsAre(
450 Field(&Instr::VMAddress, Eq(0xDEADBEEF + 8))));
451
452 InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 12);
453 XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
454 EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
455
456 InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 17);
457 XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
458 EXPECT_THAT(XRefs, UnorderedElementsAre(
459 Field(&Instr::VMAddress, Eq(0xDEADBEEF + 10)),
460 Field(&Instr::VMAddress, Eq(0xDEADBEEF + 12))));
461
462 InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 22);
463 XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
464 EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
465
466 InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 27);
467 XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
468 EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
469
470 InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 29);
471 XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
472 EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
473
474 InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 31);
475 XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
476 EXPECT_THAT(XRefs, UnorderedElementsAre(
477 Field(&Instr::VMAddress, Eq(0xDEADBEEF + 22)),
478 Field(&Instr::VMAddress, Eq(0xDEADBEEF + 29))));
479
480 InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 33);
481 XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
482 EXPECT_THAT(XRefs, UnorderedElementsAre(
483 Field(&Instr::VMAddress, Eq(0xDEADBEEF + 31))));
484
485 InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 34);
486 XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
487 EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
488
489 InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 36);
490 XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
491 EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
492
493 InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 38);
494 XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr);
495 EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty());
496}
497
Joel Galenson06e7e572018-07-13 15:19:33 +0000498TEST_F(BasicX86FileAnalysisTest, CFIProtectionInvalidTargets) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000499 if (!SuccessfullyInitialised)
500 return;
501 Analysis.parseSectionContents(
502 {
503 0x90, // 0: nop
504 0x0f, 0x0b, // 1: ud2
505 0x75, 0x00, // 3: jne 5 [+0]
506 },
507 0xDEADBEEF);
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000508 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF);
509 EXPECT_EQ(CFIProtectionStatus::FAIL_NOT_INDIRECT_CF,
510 Analysis.validateCFIProtection(Result));
511 Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 1);
512 EXPECT_EQ(CFIProtectionStatus::FAIL_NOT_INDIRECT_CF,
513 Analysis.validateCFIProtection(Result));
514 Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 3);
515 EXPECT_EQ(CFIProtectionStatus::FAIL_NOT_INDIRECT_CF,
516 Analysis.validateCFIProtection(Result));
517 Result = GraphBuilder::buildFlowGraph(Analysis, 0x12345678);
518 EXPECT_EQ(CFIProtectionStatus::FAIL_INVALID_INSTRUCTION,
519 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000520}
521
Joel Galenson06e7e572018-07-13 15:19:33 +0000522TEST_F(BasicX86FileAnalysisTest, CFIProtectionBasicFallthroughToUd2) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000523 if (!SuccessfullyInitialised)
524 return;
525 Analysis.parseSectionContents(
526 {
527 0x75, 0x02, // 0: jne 4 [+2]
528 0x0f, 0x0b, // 2: ud2
529 0xff, 0x10, // 4: callq *(%rax)
530 },
531 0xDEADBEEF);
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000532 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 4);
533 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
534 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000535}
536
Joel Galenson06e7e572018-07-13 15:19:33 +0000537TEST_F(BasicX86FileAnalysisTest, CFIProtectionBasicJumpToUd2) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000538 if (!SuccessfullyInitialised)
539 return;
540 Analysis.parseSectionContents(
541 {
542 0x75, 0x02, // 0: jne 4 [+2]
543 0xff, 0x10, // 2: callq *(%rax)
544 0x0f, 0x0b, // 4: ud2
545 },
546 0xDEADBEEF);
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000547 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 2);
548 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
549 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000550}
551
Joel Galenson06e7e572018-07-13 15:19:33 +0000552TEST_F(BasicX86FileAnalysisTest, CFIProtectionDualPathUd2) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000553 if (!SuccessfullyInitialised)
554 return;
555 Analysis.parseSectionContents(
556 {
557 0x75, 0x03, // 0: jne 5 [+3]
558 0x90, // 2: nop
559 0xff, 0x10, // 3: callq *(%rax)
560 0x0f, 0x0b, // 5: ud2
561 0x75, 0xf9, // 7: jne 2 [-7]
562 0x0f, 0x0b, // 9: ud2
563 },
564 0xDEADBEEF);
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000565 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 3);
566 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
567 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000568}
569
Joel Galenson06e7e572018-07-13 15:19:33 +0000570TEST_F(BasicX86FileAnalysisTest, CFIProtectionDualPathSingleUd2) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000571 if (!SuccessfullyInitialised)
572 return;
573 Analysis.parseSectionContents(
574 {
575 0x75, 0x05, // 0: jne 7 [+5]
576 0x90, // 2: nop
577 0xff, 0x10, // 3: callq *(%rax)
578 0x75, 0xfb, // 5: jne 2 [-5]
579 0x0f, 0x0b, // 7: ud2
580 },
581 0xDEADBEEF);
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000582 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 3);
583 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
584 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000585}
586
Joel Galenson06e7e572018-07-13 15:19:33 +0000587TEST_F(BasicX86FileAnalysisTest, CFIProtectionDualFailLimitUpwards) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000588 if (!SuccessfullyInitialised)
589 return;
590 Analysis.parseSectionContents(
591 {
592 0x75, 0x06, // 0: jne 8 [+6]
593 0x90, // 2: nop
594 0x90, // 3: nop
595 0x90, // 4: nop
596 0x90, // 5: nop
597 0xff, 0x10, // 6: callq *(%rax)
598 0x0f, 0x0b, // 8: ud2
599 },
600 0xDEADBEEF);
601 uint64_t PrevSearchLengthForConditionalBranch =
602 SearchLengthForConditionalBranch;
603 SearchLengthForConditionalBranch = 2;
604
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000605 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 6);
606 EXPECT_EQ(CFIProtectionStatus::FAIL_ORPHANS,
607 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000608
609 SearchLengthForConditionalBranch = PrevSearchLengthForConditionalBranch;
610}
611
Joel Galenson06e7e572018-07-13 15:19:33 +0000612TEST_F(BasicX86FileAnalysisTest, CFIProtectionDualFailLimitDownwards) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000613 if (!SuccessfullyInitialised)
614 return;
615 Analysis.parseSectionContents(
616 {
617 0x75, 0x02, // 0: jne 4 [+2]
618 0xff, 0x10, // 2: callq *(%rax)
619 0x90, // 4: nop
620 0x90, // 5: nop
621 0x90, // 6: nop
622 0x90, // 7: nop
623 0x0f, 0x0b, // 8: ud2
624 },
625 0xDEADBEEF);
626 uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;
627 SearchLengthForUndef = 2;
628
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000629 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 2);
630 EXPECT_EQ(CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH,
631 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000632
633 SearchLengthForUndef = PrevSearchLengthForUndef;
634}
635
Joel Galenson06e7e572018-07-13 15:19:33 +0000636TEST_F(BasicX86FileAnalysisTest, CFIProtectionGoodAndBadPaths) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000637 if (!SuccessfullyInitialised)
638 return;
639 Analysis.parseSectionContents(
640 {
641 0xeb, 0x02, // 0: jmp 4 [+2]
642 0x75, 0x02, // 2: jne 6 [+2]
643 0xff, 0x10, // 4: callq *(%rax)
644 0x0f, 0x0b, // 6: ud2
645 },
646 0xDEADBEEF);
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000647 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 4);
648 EXPECT_EQ(CFIProtectionStatus::FAIL_ORPHANS,
649 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000650}
651
Joel Galenson06e7e572018-07-13 15:19:33 +0000652TEST_F(BasicX86FileAnalysisTest, CFIProtectionWithUnconditionalJumpInFallthrough) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000653 if (!SuccessfullyInitialised)
654 return;
655 Analysis.parseSectionContents(
656 {
657 0x75, 0x04, // 0: jne 6 [+4]
658 0xeb, 0x00, // 2: jmp 4 [+0]
659 0xff, 0x10, // 4: callq *(%rax)
660 0x0f, 0x0b, // 6: ud2
661 },
662 0xDEADBEEF);
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000663 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 4);
664 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
665 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000666}
667
Joel Galenson06e7e572018-07-13 15:19:33 +0000668TEST_F(BasicX86FileAnalysisTest, CFIProtectionComplexExample) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000669 if (!SuccessfullyInitialised)
670 return;
671 // See unittests/GraphBuilder.cpp::BuildFlowGraphComplexExample for this
672 // graph.
673 Analysis.parseSectionContents(
674 {
675 0x75, 0x12, // 0: jne 20 [+18]
676 0xeb, 0x03, // 2: jmp 7 [+3]
677 0x75, 0x10, // 4: jne 22 [+16]
678 0x90, // 6: nop
679 0x90, // 7: nop
680 0x90, // 8: nop
681 0xff, 0x10, // 9: callq *(%rax)
682 0xeb, 0xfc, // 11: jmp 9 [-4]
683 0x75, 0xfa, // 13: jne 9 [-6]
684 0xe8, 0x78, 0x56, 0x34, 0x12, // 15: callq OUTOFBOUNDS [+0x12345678]
685 0x90, // 20: nop
686 0x90, // 21: nop
687 0x0f, 0x0b, // 22: ud2
688 },
689 0xDEADBEEF);
Mitch Phillips189ebb62017-11-03 20:00:05 +0000690 uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;
691 SearchLengthForUndef = 5;
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000692 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 9);
693 EXPECT_EQ(CFIProtectionStatus::FAIL_ORPHANS,
694 Analysis.validateCFIProtection(Result));
Mitch Phillips189ebb62017-11-03 20:00:05 +0000695 SearchLengthForUndef = PrevSearchLengthForUndef;
696}
697
Joel Galenson06e7e572018-07-13 15:19:33 +0000698TEST_F(BasicX86FileAnalysisTest, UndefSearchLengthOneTest) {
Mitch Phillips189ebb62017-11-03 20:00:05 +0000699 Analysis.parseSectionContents(
700 {
701 0x77, 0x0d, // 0x688118: ja 0x688127 [+12]
702 0x48, 0x89, 0xdf, // 0x68811a: mov %rbx, %rdi
703 0xff, 0xd0, // 0x68811d: callq *%rax
704 0x48, 0x89, 0xdf, // 0x68811f: mov %rbx, %rdi
705 0xe8, 0x09, 0x00, 0x00, 0x00, // 0x688122: callq 0x688130
706 0x0f, 0x0b, // 0x688127: ud2
707 },
708 0x688118);
709 uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;
710 SearchLengthForUndef = 1;
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000711 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0x68811d);
712 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
713 Analysis.validateCFIProtection(Result));
Mitch Phillips189ebb62017-11-03 20:00:05 +0000714 SearchLengthForUndef = PrevSearchLengthForUndef;
715}
716
Joel Galenson06e7e572018-07-13 15:19:33 +0000717TEST_F(BasicX86FileAnalysisTest, UndefSearchLengthOneTestFarAway) {
Mitch Phillips189ebb62017-11-03 20:00:05 +0000718 Analysis.parseSectionContents(
719 {
720 0x74, 0x73, // 0x7759eb: je 0x775a60
721 0xe9, 0x1c, 0x04, 0x00, 0x00, 0x00, // 0x7759ed: jmpq 0x775e0e
722 },
723 0x7759eb);
724
725 Analysis.parseSectionContents(
726 {
727 0x0f, 0x85, 0xb2, 0x03, 0x00, 0x00, // 0x775a56: jne 0x775e0e
728 0x48, 0x83, 0xc3, 0xf4, // 0x775a5c: add $0xfffffffffffffff4,%rbx
729 0x48, 0x8b, 0x7c, 0x24, 0x10, // 0x775a60: mov 0x10(%rsp),%rdi
730 0x48, 0x89, 0xde, // 0x775a65: mov %rbx,%rsi
731 0xff, 0xd1, // 0x775a68: callq *%rcx
732 },
733 0x775a56);
734
735 Analysis.parseSectionContents(
736 {
737 0x0f, 0x0b, // 0x775e0e: ud2
738 },
739 0x775e0e);
740 uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;
741 SearchLengthForUndef = 1;
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000742 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0x775a68);
743 EXPECT_EQ(CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH,
744 Analysis.validateCFIProtection(Result));
Mitch Phillips189ebb62017-11-03 20:00:05 +0000745 SearchLengthForUndef = 2;
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000746 Result = GraphBuilder::buildFlowGraph(Analysis, 0x775a68);
747 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
748 Analysis.validateCFIProtection(Result));
Mitch Phillips189ebb62017-11-03 20:00:05 +0000749 SearchLengthForUndef = 3;
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000750 Result = GraphBuilder::buildFlowGraph(Analysis, 0x775a68);
751 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
752 Analysis.validateCFIProtection(Result));
Mitch Phillips189ebb62017-11-03 20:00:05 +0000753 SearchLengthForUndef = PrevSearchLengthForUndef;
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000754}
755
Joel Galenson06e7e572018-07-13 15:19:33 +0000756TEST_F(BasicX86FileAnalysisTest, CFIProtectionClobberSinglePathExplicit) {
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000757 if (!SuccessfullyInitialised)
758 return;
759 Analysis.parseSectionContents(
760 {
761 0x75, 0x02, // 0: jne 4 [+2]
762 0x0f, 0x0b, // 2: ud2
763 0x48, 0x05, 0x00, 0x00, 0x00, 0x00, // 4: add $0x0, %rax
764 0xff, 0x10, // 10: callq *(%rax)
765 },
766 0xDEADBEEF);
767 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 10);
768 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
769 Analysis.validateCFIProtection(Result));
770}
771
Joel Galenson06e7e572018-07-13 15:19:33 +0000772TEST_F(BasicX86FileAnalysisTest, CFIProtectionClobberSinglePathExplicit2) {
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000773 if (!SuccessfullyInitialised)
774 return;
775 Analysis.parseSectionContents(
776 {
777 0x75, 0x02, // 0: jne 4 [+2]
778 0x0f, 0x0b, // 2: ud2
779 0x48, 0x83, 0xc0, 0x00, // 4: add $0x0, %rax
780 0xff, 0x10, // 8: callq *(%rax)
781 },
782 0xDEADBEEF);
783 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 8);
784 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
785 Analysis.validateCFIProtection(Result));
786}
787
Joel Galenson06e7e572018-07-13 15:19:33 +0000788TEST_F(BasicX86FileAnalysisTest, CFIProtectionClobberSinglePathImplicit) {
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000789 if (!SuccessfullyInitialised)
790 return;
791 Analysis.parseSectionContents(
792 {
793 0x75, 0x02, // 0: jne 4 [+2]
794 0x0f, 0x0b, // 2: ud2
795 0x05, 0x00, 0x00, 0x00, 0x00, // 4: add $0x0, %eax
796 0xff, 0x10, // 9: callq *(%rax)
797 },
798 0xDEADBEEF);
799 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 9);
800 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
801 Analysis.validateCFIProtection(Result));
802}
803
Joel Galenson06e7e572018-07-13 15:19:33 +0000804TEST_F(BasicX86FileAnalysisTest, CFIProtectionClobberDualPathImplicit) {
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000805 if (!SuccessfullyInitialised)
806 return;
807 Analysis.parseSectionContents(
808 {
809 0x75, 0x04, // 0: jne 6 [+4]
810 0x0f, 0x31, // 2: rdtsc (note: affects eax)
811 0xff, 0x10, // 4: callq *(%rax)
812 0x0f, 0x0b, // 6: ud2
813 0x75, 0xf9, // 8: jne 2 [-7]
814 0x0f, 0x0b, // 10: ud2
815 },
816 0xDEADBEEF);
817 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 4);
818 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
819 Analysis.validateCFIProtection(Result));
820}
821
Joel Galenson06e7e572018-07-13 15:19:33 +0000822TEST_F(BasicAArch64FileAnalysisTest, AArch64BasicUnprotected) {
823 if (!SuccessfullyInitialised)
824 return;
825 Analysis.parseSectionContents(
826 {
827 0x00, 0x01, 0x3f, 0xd6, // 0: blr x8
828 },
829 0xDEADBEEF);
830 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF);
831 EXPECT_EQ(CFIProtectionStatus::FAIL_ORPHANS,
832 Analysis.validateCFIProtection(Result));
833}
834
835TEST_F(BasicAArch64FileAnalysisTest, AArch64BasicProtected) {
836 if (!SuccessfullyInitialised)
837 return;
838 Analysis.parseSectionContents(
839 {
840 0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
841 0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
842 0x00, 0x01, 0x3f, 0xd6, // 8: blr x8
843 },
844 0xDEADBEEF);
845 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 8);
846 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
847 Analysis.validateCFIProtection(Result));
848}
849
850TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberBasic) {
851 if (!SuccessfullyInitialised)
852 return;
853 Analysis.parseSectionContents(
854 {
855 0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
856 0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
857 0x08, 0x05, 0x00, 0x91, // 8: add x8, x8, #1
858 0x00, 0x01, 0x3f, 0xd6, // 12: blr x8
859 },
860 0xDEADBEEF);
861 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 12);
862 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
863 Analysis.validateCFIProtection(Result));
864}
865
866TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberOneLoad) {
867 if (!SuccessfullyInitialised)
868 return;
869 Analysis.parseSectionContents(
870 {
871 0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
872 0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
873 0x21, 0x09, 0x40, 0xf9, // 8: ldr x1, [x9,#16]
874 0x20, 0x00, 0x1f, 0xd6, // 12: br x1
875 },
876 0xDEADBEEF);
877 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 12);
878 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
879 Analysis.validateCFIProtection(Result));
880}
881
882TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberLoadAddGood) {
883 if (!SuccessfullyInitialised)
884 return;
885 Analysis.parseSectionContents(
886 {
887 0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
888 0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
889 0x21, 0x04, 0x00, 0x91, // 8: add x1, x1, #1
890 0x21, 0x09, 0x40, 0xf9, // 12: ldr x1, [x9,#16]
891 0x20, 0x00, 0x1f, 0xd6, // 16: br x1
892 },
893 0xDEADBEEF);
894 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 16);
895 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
896 Analysis.validateCFIProtection(Result));
897}
898
899TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberLoadAddBad) {
900 if (!SuccessfullyInitialised)
901 return;
902 Analysis.parseSectionContents(
903 {
904 0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
905 0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
906 0x21, 0x09, 0x40, 0xf9, // 8: ldr x1, [x9,#16]
907 0x21, 0x04, 0x00, 0x91, // 12: add x1, x1, #1
908 0x20, 0x00, 0x1f, 0xd6, // 16: br x1
909 },
910 0xDEADBEEF);
911 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 16);
912 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
913 Analysis.validateCFIProtection(Result));
914}
915
916TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberLoadAddBad2) {
917 if (!SuccessfullyInitialised)
918 return;
919 Analysis.parseSectionContents(
920 {
921 0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
922 0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
923 0x29, 0x04, 0x00, 0x91, // 16: add x9, x1, #1
924 0x21, 0x09, 0x40, 0xf9, // 12: ldr x1, [x9,#16]
925 0x20, 0x00, 0x1f, 0xd6, // 16: br x1
926 },
927 0xDEADBEEF);
928 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 16);
929 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
930 Analysis.validateCFIProtection(Result));
931}
932
933TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberTwoLoads) {
934 if (!SuccessfullyInitialised)
935 return;
936 Analysis.parseSectionContents(
937 {
938 0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
939 0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
940 0x21, 0x09, 0x40, 0xf9, // 8: ldr x1, [x9,#16]
941 0x21, 0x08, 0x40, 0xf9, // 12: ldr x1, [x1,#16]
942 0x20, 0x00, 0x1f, 0xd6, // 16: br x1
943 },
944 0xDEADBEEF);
945 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 16);
946 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
947 Analysis.validateCFIProtection(Result));
948}
949
950TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberUnrelatedSecondLoad) {
951 if (!SuccessfullyInitialised)
952 return;
953 Analysis.parseSectionContents(
954 {
955 0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
956 0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
957 0x21, 0x09, 0x40, 0xf9, // 8: ldr x1, [x9,#16]
958 0x21, 0x09, 0x40, 0xf9, // 12: ldr x1, [x9,#16]
959 0x20, 0x00, 0x1f, 0xd6, // 16: br x1
960 },
961 0xDEADBEEF);
962 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 16);
963 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
964 Analysis.validateCFIProtection(Result));
965}
966
967TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberUnrelatedLoads) {
968 if (!SuccessfullyInitialised)
969 return;
970 Analysis.parseSectionContents(
971 {
972 0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
973 0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
974 0x22, 0x09, 0x40, 0xf9, // 8: ldr x2, [x9,#16]
975 0x22, 0x08, 0x40, 0xf9, // 12: ldr x2, [x1,#16]
976 0x20, 0x00, 0x1f, 0xd6, // 16: br x1
977 },
978 0xDEADBEEF);
979 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 16);
980 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
981 Analysis.validateCFIProtection(Result));
982}
983
984TEST_F(BasicAArch64FileAnalysisTest, AArch64GoodAndBadPaths) {
985 if (!SuccessfullyInitialised)
986 return;
987 Analysis.parseSectionContents(
988 {
989 0x03, 0x00, 0x00, 0x14, // 0: b 12
990 0x49, 0x00, 0x00, 0x54, // 4: b.ls 8
991 0x20, 0x00, 0x20, 0xd4, // 8: brk #0x1
992 0x20, 0x00, 0x1f, 0xd6, // 12: br x1
993 },
994 0xDEADBEEF);
995 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 12);
996 EXPECT_EQ(CFIProtectionStatus::FAIL_ORPHANS,
997 Analysis.validateCFIProtection(Result));
998}
999
1000TEST_F(BasicAArch64FileAnalysisTest, AArch64TwoPaths) {
1001 if (!SuccessfullyInitialised)
1002 return;
1003 Analysis.parseSectionContents(
1004 {
1005 0xc9, 0x00, 0x00, 0x54, // 0: b.ls 24
1006 0x21, 0x08, 0x40, 0xf9, // 4: ldr x1, [x1,#16]
1007 0x03, 0x00, 0x00, 0x14, // 8: b 12
1008 0x69, 0x00, 0x00, 0x54, // 12: b.ls 12
1009 0x21, 0x08, 0x40, 0xf9, // 16: ldr x1, [x1,#16]
1010 0x20, 0x00, 0x1f, 0xd6, // 20: br x1
1011 0x20, 0x00, 0x20, 0xd4, // 24: brk #0x1
1012 },
1013 0xDEADBEEF);
1014 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 20);
1015 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
1016 Analysis.validateCFIProtection(Result));
1017}
1018
1019TEST_F(BasicAArch64FileAnalysisTest, AArch64TwoPathsBadLoad1) {
1020 if (!SuccessfullyInitialised)
1021 return;
1022 Analysis.parseSectionContents(
1023 {
1024 0xe9, 0x00, 0x00, 0x54, // 0: b.ls 28
1025 0x21, 0x08, 0x40, 0xf9, // 4: ldr x1, [x1,#16]
1026 0x21, 0x08, 0x40, 0xf9, // 8: ldr x1, [x1,#16]
1027 0x03, 0x00, 0x00, 0x14, // 12: b 12
1028 0x69, 0x00, 0x00, 0x54, // 16: b.ls 12
1029 0x21, 0x08, 0x40, 0xf9, // 20: ldr x1, [x1,#16]
1030 0x20, 0x00, 0x1f, 0xd6, // 24: br x1
1031 0x20, 0x00, 0x20, 0xd4, // 28: brk #0x1
1032 },
1033 0xDEADBEEF);
1034 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 24);
1035 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
1036 Analysis.validateCFIProtection(Result));
1037}
1038
1039TEST_F(BasicAArch64FileAnalysisTest, AArch64TwoPathsBadLoad2) {
1040 if (!SuccessfullyInitialised)
1041 return;
1042 Analysis.parseSectionContents(
1043 {
1044 0xe9, 0x00, 0x00, 0x54, // 0: b.ls 28
1045 0x21, 0x08, 0x40, 0xf9, // 4: ldr x1, [x1,#16]
1046 0x03, 0x00, 0x00, 0x14, // 8: b 12
1047 0x89, 0x00, 0x00, 0x54, // 12: b.ls 16
1048 0x21, 0x08, 0x40, 0xf9, // 16: ldr x1, [x1,#16]
1049 0x21, 0x08, 0x40, 0xf9, // 20: ldr x1, [x1,#16]
1050 0x20, 0x00, 0x1f, 0xd6, // 24: br x1
1051 0x20, 0x00, 0x20, 0xd4, // 28: brk #0x1
1052 },
1053 0xDEADBEEF);
1054 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, 0xDEADBEEF + 24);
1055 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
1056 Analysis.validateCFIProtection(Result));
1057}
1058
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +00001059} // anonymous namespace
1060} // end namespace cfi_verify
1061} // end namespace llvm
1062
1063int main(int argc, char **argv) {
1064 ::testing::InitGoogleTest(&argc, argv);
1065 llvm::cl::ParseCommandLineOptions(argc, argv);
1066
1067 llvm::InitializeAllTargetInfos();
1068 llvm::InitializeAllTargetMCs();
1069 llvm::InitializeAllAsmParsers();
1070 llvm::InitializeAllDisassemblers();
1071
1072 return RUN_ALL_TESTS();
1073}