blob: e38ac9264c8dfa18124e94d29f20f62ae52fe330 [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,
Alexey Lapshin77fc1f62019-02-27 13:17:36 +000054 object::SectionedAddress Address) {
55 FileAnalysis::parseSectionContents(SectionBytes, Address);
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000056 }
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 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000109 {0xDEADBEEF, 0x0});
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000110
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 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000213 {0xDEADBEEF, 0x0});
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000214 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 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000243 {0xDEADBEEF, 0x0});
Vlad Tsyrklevich0ee26322017-10-11 23:17:29 +0000244
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 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000278 {0xDEADBEEF, 0x0});
Vlad Tsyrklevich0ee26322017-10-11 23:17:29 +0000279
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 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000325 {0xDEADBEEF, 0x0});
Vlad Tsyrklevich0ee26322017-10-11 23:17:29 +0000326
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 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000415 {0xDEADBEEF, 0x0});
Vlad Tsyrklevich0ee26322017-10-11 23:17:29 +0000416 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 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000506 {0xDEADBEEF, 0x0});
507 GraphResult Result =
508 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000509 EXPECT_EQ(CFIProtectionStatus::FAIL_NOT_INDIRECT_CF,
510 Analysis.validateCFIProtection(Result));
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000511 Result = GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 1, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000512 EXPECT_EQ(CFIProtectionStatus::FAIL_NOT_INDIRECT_CF,
513 Analysis.validateCFIProtection(Result));
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000514 Result = GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 3, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000515 EXPECT_EQ(CFIProtectionStatus::FAIL_NOT_INDIRECT_CF,
516 Analysis.validateCFIProtection(Result));
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000517 Result = GraphBuilder::buildFlowGraph(Analysis, {0x12345678, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000518 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 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000531 {0xDEADBEEF, 0x0});
532 GraphResult Result =
533 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 4, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000534 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
535 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000536}
537
Joel Galenson06e7e572018-07-13 15:19:33 +0000538TEST_F(BasicX86FileAnalysisTest, CFIProtectionBasicJumpToUd2) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000539 if (!SuccessfullyInitialised)
540 return;
541 Analysis.parseSectionContents(
542 {
543 0x75, 0x02, // 0: jne 4 [+2]
544 0xff, 0x10, // 2: callq *(%rax)
545 0x0f, 0x0b, // 4: ud2
546 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000547 {0xDEADBEEF, 0x0});
548 GraphResult Result =
549 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 2, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000550 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
551 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000552}
553
Joel Galenson06e7e572018-07-13 15:19:33 +0000554TEST_F(BasicX86FileAnalysisTest, CFIProtectionDualPathUd2) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000555 if (!SuccessfullyInitialised)
556 return;
557 Analysis.parseSectionContents(
558 {
559 0x75, 0x03, // 0: jne 5 [+3]
560 0x90, // 2: nop
561 0xff, 0x10, // 3: callq *(%rax)
562 0x0f, 0x0b, // 5: ud2
563 0x75, 0xf9, // 7: jne 2 [-7]
564 0x0f, 0x0b, // 9: ud2
565 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000566 {0xDEADBEEF, 0x0});
567 GraphResult Result =
568 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 3, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000569 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
570 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000571}
572
Joel Galenson06e7e572018-07-13 15:19:33 +0000573TEST_F(BasicX86FileAnalysisTest, CFIProtectionDualPathSingleUd2) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000574 if (!SuccessfullyInitialised)
575 return;
576 Analysis.parseSectionContents(
577 {
578 0x75, 0x05, // 0: jne 7 [+5]
579 0x90, // 2: nop
580 0xff, 0x10, // 3: callq *(%rax)
581 0x75, 0xfb, // 5: jne 2 [-5]
582 0x0f, 0x0b, // 7: ud2
583 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000584 {0xDEADBEEF, 0x0});
585 GraphResult Result =
586 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 3, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000587 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
588 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000589}
590
Joel Galenson06e7e572018-07-13 15:19:33 +0000591TEST_F(BasicX86FileAnalysisTest, CFIProtectionDualFailLimitUpwards) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000592 if (!SuccessfullyInitialised)
593 return;
594 Analysis.parseSectionContents(
595 {
596 0x75, 0x06, // 0: jne 8 [+6]
597 0x90, // 2: nop
598 0x90, // 3: nop
599 0x90, // 4: nop
600 0x90, // 5: nop
601 0xff, 0x10, // 6: callq *(%rax)
602 0x0f, 0x0b, // 8: ud2
603 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000604 {0xDEADBEEF, 0x0});
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000605 uint64_t PrevSearchLengthForConditionalBranch =
606 SearchLengthForConditionalBranch;
607 SearchLengthForConditionalBranch = 2;
608
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000609 GraphResult Result =
610 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 6, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000611 EXPECT_EQ(CFIProtectionStatus::FAIL_ORPHANS,
612 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000613
614 SearchLengthForConditionalBranch = PrevSearchLengthForConditionalBranch;
615}
616
Joel Galenson06e7e572018-07-13 15:19:33 +0000617TEST_F(BasicX86FileAnalysisTest, CFIProtectionDualFailLimitDownwards) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000618 if (!SuccessfullyInitialised)
619 return;
620 Analysis.parseSectionContents(
621 {
622 0x75, 0x02, // 0: jne 4 [+2]
623 0xff, 0x10, // 2: callq *(%rax)
624 0x90, // 4: nop
625 0x90, // 5: nop
626 0x90, // 6: nop
627 0x90, // 7: nop
628 0x0f, 0x0b, // 8: ud2
629 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000630 {0xDEADBEEF, 0x0});
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000631 uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;
632 SearchLengthForUndef = 2;
633
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000634 GraphResult Result =
635 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 2, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000636 EXPECT_EQ(CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH,
637 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000638
639 SearchLengthForUndef = PrevSearchLengthForUndef;
640}
641
Joel Galenson06e7e572018-07-13 15:19:33 +0000642TEST_F(BasicX86FileAnalysisTest, CFIProtectionGoodAndBadPaths) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000643 if (!SuccessfullyInitialised)
644 return;
645 Analysis.parseSectionContents(
646 {
647 0xeb, 0x02, // 0: jmp 4 [+2]
648 0x75, 0x02, // 2: jne 6 [+2]
649 0xff, 0x10, // 4: callq *(%rax)
650 0x0f, 0x0b, // 6: ud2
651 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000652 {0xDEADBEEF, 0x0});
653 GraphResult Result =
654 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 4, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000655 EXPECT_EQ(CFIProtectionStatus::FAIL_ORPHANS,
656 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000657}
658
Joel Galenson06e7e572018-07-13 15:19:33 +0000659TEST_F(BasicX86FileAnalysisTest, CFIProtectionWithUnconditionalJumpInFallthrough) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000660 if (!SuccessfullyInitialised)
661 return;
662 Analysis.parseSectionContents(
663 {
664 0x75, 0x04, // 0: jne 6 [+4]
665 0xeb, 0x00, // 2: jmp 4 [+0]
666 0xff, 0x10, // 4: callq *(%rax)
667 0x0f, 0x0b, // 6: ud2
668 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000669 {0xDEADBEEF, 0x0});
670 GraphResult Result =
671 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 4, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000672 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
673 Analysis.validateCFIProtection(Result));
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000674}
675
Joel Galenson06e7e572018-07-13 15:19:33 +0000676TEST_F(BasicX86FileAnalysisTest, CFIProtectionComplexExample) {
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000677 if (!SuccessfullyInitialised)
678 return;
679 // See unittests/GraphBuilder.cpp::BuildFlowGraphComplexExample for this
680 // graph.
681 Analysis.parseSectionContents(
682 {
683 0x75, 0x12, // 0: jne 20 [+18]
684 0xeb, 0x03, // 2: jmp 7 [+3]
685 0x75, 0x10, // 4: jne 22 [+16]
686 0x90, // 6: nop
687 0x90, // 7: nop
688 0x90, // 8: nop
689 0xff, 0x10, // 9: callq *(%rax)
690 0xeb, 0xfc, // 11: jmp 9 [-4]
691 0x75, 0xfa, // 13: jne 9 [-6]
692 0xe8, 0x78, 0x56, 0x34, 0x12, // 15: callq OUTOFBOUNDS [+0x12345678]
693 0x90, // 20: nop
694 0x90, // 21: nop
695 0x0f, 0x0b, // 22: ud2
696 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000697 {0xDEADBEEF, 0x0});
Mitch Phillips189ebb62017-11-03 20:00:05 +0000698 uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;
699 SearchLengthForUndef = 5;
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000700 GraphResult Result =
701 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 9, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000702 EXPECT_EQ(CFIProtectionStatus::FAIL_ORPHANS,
703 Analysis.validateCFIProtection(Result));
Mitch Phillips189ebb62017-11-03 20:00:05 +0000704 SearchLengthForUndef = PrevSearchLengthForUndef;
705}
706
Joel Galenson06e7e572018-07-13 15:19:33 +0000707TEST_F(BasicX86FileAnalysisTest, UndefSearchLengthOneTest) {
Mitch Phillips189ebb62017-11-03 20:00:05 +0000708 Analysis.parseSectionContents(
709 {
710 0x77, 0x0d, // 0x688118: ja 0x688127 [+12]
711 0x48, 0x89, 0xdf, // 0x68811a: mov %rbx, %rdi
712 0xff, 0xd0, // 0x68811d: callq *%rax
713 0x48, 0x89, 0xdf, // 0x68811f: mov %rbx, %rdi
714 0xe8, 0x09, 0x00, 0x00, 0x00, // 0x688122: callq 0x688130
715 0x0f, 0x0b, // 0x688127: ud2
716 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000717 {0x688118, 0x0});
Mitch Phillips189ebb62017-11-03 20:00:05 +0000718 uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;
719 SearchLengthForUndef = 1;
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000720 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, {0x68811d, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000721 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
722 Analysis.validateCFIProtection(Result));
Mitch Phillips189ebb62017-11-03 20:00:05 +0000723 SearchLengthForUndef = PrevSearchLengthForUndef;
724}
725
Joel Galenson06e7e572018-07-13 15:19:33 +0000726TEST_F(BasicX86FileAnalysisTest, UndefSearchLengthOneTestFarAway) {
Mitch Phillips189ebb62017-11-03 20:00:05 +0000727 Analysis.parseSectionContents(
728 {
729 0x74, 0x73, // 0x7759eb: je 0x775a60
730 0xe9, 0x1c, 0x04, 0x00, 0x00, 0x00, // 0x7759ed: jmpq 0x775e0e
731 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000732 {0x7759eb, 0x0});
Mitch Phillips189ebb62017-11-03 20:00:05 +0000733
734 Analysis.parseSectionContents(
735 {
736 0x0f, 0x85, 0xb2, 0x03, 0x00, 0x00, // 0x775a56: jne 0x775e0e
737 0x48, 0x83, 0xc3, 0xf4, // 0x775a5c: add $0xfffffffffffffff4,%rbx
738 0x48, 0x8b, 0x7c, 0x24, 0x10, // 0x775a60: mov 0x10(%rsp),%rdi
739 0x48, 0x89, 0xde, // 0x775a65: mov %rbx,%rsi
740 0xff, 0xd1, // 0x775a68: callq *%rcx
741 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000742 {0x775a56, 0x0});
Mitch Phillips189ebb62017-11-03 20:00:05 +0000743
744 Analysis.parseSectionContents(
745 {
746 0x0f, 0x0b, // 0x775e0e: ud2
747 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000748 {0x775e0e, 0x0});
Mitch Phillips189ebb62017-11-03 20:00:05 +0000749 uint64_t PrevSearchLengthForUndef = SearchLengthForUndef;
750 SearchLengthForUndef = 1;
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000751 GraphResult Result = GraphBuilder::buildFlowGraph(Analysis, {0x775a68, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000752 EXPECT_EQ(CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH,
753 Analysis.validateCFIProtection(Result));
Mitch Phillips189ebb62017-11-03 20:00:05 +0000754 SearchLengthForUndef = 2;
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000755 Result = GraphBuilder::buildFlowGraph(Analysis, {0x775a68, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000756 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
757 Analysis.validateCFIProtection(Result));
Mitch Phillips189ebb62017-11-03 20:00:05 +0000758 SearchLengthForUndef = 3;
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000759 Result = GraphBuilder::buildFlowGraph(Analysis, {0x775a68, 0x0});
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000760 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
761 Analysis.validateCFIProtection(Result));
Mitch Phillips189ebb62017-11-03 20:00:05 +0000762 SearchLengthForUndef = PrevSearchLengthForUndef;
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000763}
764
Joel Galenson06e7e572018-07-13 15:19:33 +0000765TEST_F(BasicX86FileAnalysisTest, CFIProtectionClobberSinglePathExplicit) {
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000766 if (!SuccessfullyInitialised)
767 return;
768 Analysis.parseSectionContents(
769 {
770 0x75, 0x02, // 0: jne 4 [+2]
771 0x0f, 0x0b, // 2: ud2
772 0x48, 0x05, 0x00, 0x00, 0x00, 0x00, // 4: add $0x0, %rax
773 0xff, 0x10, // 10: callq *(%rax)
774 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000775 {0xDEADBEEF, 0x0});
776 GraphResult Result =
777 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 10, 0x0});
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000778 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
779 Analysis.validateCFIProtection(Result));
780}
781
Joel Galenson06e7e572018-07-13 15:19:33 +0000782TEST_F(BasicX86FileAnalysisTest, CFIProtectionClobberSinglePathExplicit2) {
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000783 if (!SuccessfullyInitialised)
784 return;
785 Analysis.parseSectionContents(
786 {
787 0x75, 0x02, // 0: jne 4 [+2]
788 0x0f, 0x0b, // 2: ud2
789 0x48, 0x83, 0xc0, 0x00, // 4: add $0x0, %rax
790 0xff, 0x10, // 8: callq *(%rax)
791 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000792 {0xDEADBEEF, 0x0});
793 GraphResult Result =
794 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 8, 0x0});
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000795 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
796 Analysis.validateCFIProtection(Result));
797}
798
Joel Galenson06e7e572018-07-13 15:19:33 +0000799TEST_F(BasicX86FileAnalysisTest, CFIProtectionClobberSinglePathImplicit) {
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000800 if (!SuccessfullyInitialised)
801 return;
802 Analysis.parseSectionContents(
803 {
804 0x75, 0x02, // 0: jne 4 [+2]
805 0x0f, 0x0b, // 2: ud2
806 0x05, 0x00, 0x00, 0x00, 0x00, // 4: add $0x0, %eax
807 0xff, 0x10, // 9: callq *(%rax)
808 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000809 {0xDEADBEEF, 0x0});
810 GraphResult Result =
811 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 9, 0x0});
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000812 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
813 Analysis.validateCFIProtection(Result));
814}
815
Joel Galenson06e7e572018-07-13 15:19:33 +0000816TEST_F(BasicX86FileAnalysisTest, CFIProtectionClobberDualPathImplicit) {
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000817 if (!SuccessfullyInitialised)
818 return;
819 Analysis.parseSectionContents(
820 {
821 0x75, 0x04, // 0: jne 6 [+4]
822 0x0f, 0x31, // 2: rdtsc (note: affects eax)
823 0xff, 0x10, // 4: callq *(%rax)
824 0x0f, 0x0b, // 6: ud2
825 0x75, 0xf9, // 8: jne 2 [-7]
826 0x0f, 0x0b, // 10: ud2
827 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000828 {0xDEADBEEF, 0x0});
829 GraphResult Result =
830 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 4, 0x0});
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000831 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
832 Analysis.validateCFIProtection(Result));
833}
834
Joel Galenson06e7e572018-07-13 15:19:33 +0000835TEST_F(BasicAArch64FileAnalysisTest, AArch64BasicUnprotected) {
836 if (!SuccessfullyInitialised)
837 return;
838 Analysis.parseSectionContents(
839 {
840 0x00, 0x01, 0x3f, 0xd6, // 0: blr x8
841 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000842 {0xDEADBEEF, 0x0});
843 GraphResult Result =
844 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF, 0x0});
Joel Galenson06e7e572018-07-13 15:19:33 +0000845 EXPECT_EQ(CFIProtectionStatus::FAIL_ORPHANS,
846 Analysis.validateCFIProtection(Result));
847}
848
849TEST_F(BasicAArch64FileAnalysisTest, AArch64BasicProtected) {
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 0x00, 0x01, 0x3f, 0xd6, // 8: blr x8
857 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000858 {0xDEADBEEF, 0x0});
859 GraphResult Result =
860 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 8, 0x0});
Joel Galenson06e7e572018-07-13 15:19:33 +0000861 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
862 Analysis.validateCFIProtection(Result));
863}
864
865TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberBasic) {
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 0x08, 0x05, 0x00, 0x91, // 8: add x8, x8, #1
873 0x00, 0x01, 0x3f, 0xd6, // 12: blr x8
874 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000875 {0xDEADBEEF, 0x0});
876 GraphResult Result =
877 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 12, 0x0});
Joel Galenson06e7e572018-07-13 15:19:33 +0000878 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
879 Analysis.validateCFIProtection(Result));
880}
881
882TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberOneLoad) {
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, 0x09, 0x40, 0xf9, // 8: ldr x1, [x9,#16]
890 0x20, 0x00, 0x1f, 0xd6, // 12: br x1
891 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000892 {0xDEADBEEF, 0x0});
893 GraphResult Result =
894 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 12, 0x0});
Joel Galenson06e7e572018-07-13 15:19:33 +0000895 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
896 Analysis.validateCFIProtection(Result));
897}
898
899TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberLoadAddGood) {
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, 0x04, 0x00, 0x91, // 8: add x1, x1, #1
907 0x21, 0x09, 0x40, 0xf9, // 12: ldr x1, [x9,#16]
908 0x20, 0x00, 0x1f, 0xd6, // 16: br x1
909 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000910 {0xDEADBEEF, 0x0});
911 GraphResult Result =
912 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 16, 0x0});
Joel Galenson06e7e572018-07-13 15:19:33 +0000913 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
914 Analysis.validateCFIProtection(Result));
915}
916
917TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberLoadAddBad) {
918 if (!SuccessfullyInitialised)
919 return;
920 Analysis.parseSectionContents(
921 {
922 0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
923 0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
924 0x21, 0x09, 0x40, 0xf9, // 8: ldr x1, [x9,#16]
925 0x21, 0x04, 0x00, 0x91, // 12: add x1, x1, #1
926 0x20, 0x00, 0x1f, 0xd6, // 16: br x1
927 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000928 {0xDEADBEEF, 0x0});
929 GraphResult Result =
930 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 16, 0x0});
Joel Galenson06e7e572018-07-13 15:19:33 +0000931 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
932 Analysis.validateCFIProtection(Result));
933}
934
935TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberLoadAddBad2) {
936 if (!SuccessfullyInitialised)
937 return;
938 Analysis.parseSectionContents(
939 {
940 0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
941 0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
942 0x29, 0x04, 0x00, 0x91, // 16: add x9, x1, #1
943 0x21, 0x09, 0x40, 0xf9, // 12: ldr x1, [x9,#16]
944 0x20, 0x00, 0x1f, 0xd6, // 16: br x1
945 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000946 {0xDEADBEEF, 0x0});
947 GraphResult Result =
948 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 16, 0x0});
Joel Galenson06e7e572018-07-13 15:19:33 +0000949 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
950 Analysis.validateCFIProtection(Result));
951}
952
953TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberTwoLoads) {
954 if (!SuccessfullyInitialised)
955 return;
956 Analysis.parseSectionContents(
957 {
958 0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
959 0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
960 0x21, 0x09, 0x40, 0xf9, // 8: ldr x1, [x9,#16]
961 0x21, 0x08, 0x40, 0xf9, // 12: ldr x1, [x1,#16]
962 0x20, 0x00, 0x1f, 0xd6, // 16: br x1
963 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000964 {0xDEADBEEF, 0x0});
965 GraphResult Result =
966 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 16, 0x0});
Joel Galenson06e7e572018-07-13 15:19:33 +0000967 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
968 Analysis.validateCFIProtection(Result));
969}
970
971TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberUnrelatedSecondLoad) {
972 if (!SuccessfullyInitialised)
973 return;
974 Analysis.parseSectionContents(
975 {
976 0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
977 0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
978 0x21, 0x09, 0x40, 0xf9, // 8: ldr x1, [x9,#16]
979 0x21, 0x09, 0x40, 0xf9, // 12: ldr x1, [x9,#16]
980 0x20, 0x00, 0x1f, 0xd6, // 16: br x1
981 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000982 {0xDEADBEEF, 0x0});
983 GraphResult Result =
984 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 16, 0x0});
Joel Galenson06e7e572018-07-13 15:19:33 +0000985 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
986 Analysis.validateCFIProtection(Result));
987}
988
989TEST_F(BasicAArch64FileAnalysisTest, AArch64ClobberUnrelatedLoads) {
990 if (!SuccessfullyInitialised)
991 return;
992 Analysis.parseSectionContents(
993 {
994 0x49, 0x00, 0x00, 0x54, // 0: b.ls 8
995 0x20, 0x00, 0x20, 0xd4, // 4: brk #0x1
996 0x22, 0x09, 0x40, 0xf9, // 8: ldr x2, [x9,#16]
997 0x22, 0x08, 0x40, 0xf9, // 12: ldr x2, [x1,#16]
998 0x20, 0x00, 0x1f, 0xd6, // 16: br x1
999 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +00001000 {0xDEADBEEF, 0x0});
1001 GraphResult Result =
1002 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 16, 0x0});
Joel Galenson06e7e572018-07-13 15:19:33 +00001003 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
1004 Analysis.validateCFIProtection(Result));
1005}
1006
1007TEST_F(BasicAArch64FileAnalysisTest, AArch64GoodAndBadPaths) {
1008 if (!SuccessfullyInitialised)
1009 return;
1010 Analysis.parseSectionContents(
1011 {
1012 0x03, 0x00, 0x00, 0x14, // 0: b 12
1013 0x49, 0x00, 0x00, 0x54, // 4: b.ls 8
1014 0x20, 0x00, 0x20, 0xd4, // 8: brk #0x1
1015 0x20, 0x00, 0x1f, 0xd6, // 12: br x1
1016 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +00001017 {0xDEADBEEF, 0x0});
1018 GraphResult Result =
1019 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 12, 0x0});
Joel Galenson06e7e572018-07-13 15:19:33 +00001020 EXPECT_EQ(CFIProtectionStatus::FAIL_ORPHANS,
1021 Analysis.validateCFIProtection(Result));
1022}
1023
1024TEST_F(BasicAArch64FileAnalysisTest, AArch64TwoPaths) {
1025 if (!SuccessfullyInitialised)
1026 return;
1027 Analysis.parseSectionContents(
1028 {
1029 0xc9, 0x00, 0x00, 0x54, // 0: b.ls 24
1030 0x21, 0x08, 0x40, 0xf9, // 4: ldr x1, [x1,#16]
1031 0x03, 0x00, 0x00, 0x14, // 8: b 12
1032 0x69, 0x00, 0x00, 0x54, // 12: b.ls 12
1033 0x21, 0x08, 0x40, 0xf9, // 16: ldr x1, [x1,#16]
1034 0x20, 0x00, 0x1f, 0xd6, // 20: br x1
1035 0x20, 0x00, 0x20, 0xd4, // 24: brk #0x1
1036 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +00001037 {0xDEADBEEF, 0x0});
1038 GraphResult Result =
1039 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 20, 0x0});
Joel Galenson06e7e572018-07-13 15:19:33 +00001040 EXPECT_EQ(CFIProtectionStatus::PROTECTED,
1041 Analysis.validateCFIProtection(Result));
1042}
1043
1044TEST_F(BasicAArch64FileAnalysisTest, AArch64TwoPathsBadLoad1) {
1045 if (!SuccessfullyInitialised)
1046 return;
1047 Analysis.parseSectionContents(
1048 {
1049 0xe9, 0x00, 0x00, 0x54, // 0: b.ls 28
1050 0x21, 0x08, 0x40, 0xf9, // 4: ldr x1, [x1,#16]
1051 0x21, 0x08, 0x40, 0xf9, // 8: ldr x1, [x1,#16]
1052 0x03, 0x00, 0x00, 0x14, // 12: b 12
1053 0x69, 0x00, 0x00, 0x54, // 16: b.ls 12
1054 0x21, 0x08, 0x40, 0xf9, // 20: ldr x1, [x1,#16]
1055 0x20, 0x00, 0x1f, 0xd6, // 24: br x1
1056 0x20, 0x00, 0x20, 0xd4, // 28: brk #0x1
1057 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +00001058 {0xDEADBEEF, 0x0});
1059 GraphResult Result =
1060 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 24, 0x0});
Joel Galenson06e7e572018-07-13 15:19:33 +00001061 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
1062 Analysis.validateCFIProtection(Result));
1063}
1064
1065TEST_F(BasicAArch64FileAnalysisTest, AArch64TwoPathsBadLoad2) {
1066 if (!SuccessfullyInitialised)
1067 return;
1068 Analysis.parseSectionContents(
1069 {
1070 0xe9, 0x00, 0x00, 0x54, // 0: b.ls 28
1071 0x21, 0x08, 0x40, 0xf9, // 4: ldr x1, [x1,#16]
1072 0x03, 0x00, 0x00, 0x14, // 8: b 12
1073 0x89, 0x00, 0x00, 0x54, // 12: b.ls 16
1074 0x21, 0x08, 0x40, 0xf9, // 16: ldr x1, [x1,#16]
1075 0x21, 0x08, 0x40, 0xf9, // 20: ldr x1, [x1,#16]
1076 0x20, 0x00, 0x1f, 0xd6, // 24: br x1
1077 0x20, 0x00, 0x20, 0xd4, // 28: brk #0x1
1078 },
Alexey Lapshin77fc1f62019-02-27 13:17:36 +00001079 {0xDEADBEEF, 0x0});
1080 GraphResult Result =
1081 GraphBuilder::buildFlowGraph(Analysis, {0xDEADBEEF + 24, 0x0});
Joel Galenson06e7e572018-07-13 15:19:33 +00001082 EXPECT_EQ(CFIProtectionStatus::FAIL_REGISTER_CLOBBERED,
1083 Analysis.validateCFIProtection(Result));
1084}
1085
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +00001086} // anonymous namespace
1087} // end namespace cfi_verify
1088} // end namespace llvm
1089
1090int main(int argc, char **argv) {
1091 ::testing::InitGoogleTest(&argc, argv);
1092 llvm::cl::ParseCommandLineOptions(argc, argv);
1093
1094 llvm::InitializeAllTargetInfos();
1095 llvm::InitializeAllTargetMCs();
1096 llvm::InitializeAllAsmParsers();
1097 llvm::InitializeAllDisassemblers();
1098
1099 return RUN_ALL_TESTS();
1100}