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