blob: 01f03158d6bb27b969fa295585109b1560fb5ff8 [file] [log] [blame]
Vlad Tsyrklevich31b45312017-09-20 20:38:14 +00001//===-- llvm-cfi-verify.cpp - CFI Verification tool for LLVM --------------===//
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// This tool verifies Control Flow Integrity (CFI) instrumentation by static
11// binary anaylsis. See the design document in /docs/CFIVerify.rst for more
12// information.
13//
14// This tool is currently incomplete. It currently only does disassembly for
15// object files, and searches through the code for indirect control flow
16// instructions, printing them once found.
17//
18//===----------------------------------------------------------------------===//
19
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000020#include "lib/FileAnalysis.h"
Vlad Tsyrklevichb5488a22017-10-10 20:59:08 +000021
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000022#include "llvm/BinaryFormat/ELF.h"
23#include "llvm/Support/CommandLine.h"
24#include "llvm/Support/Error.h"
Mitch Phillips7db6f7a2017-10-31 23:20:05 +000025#include "llvm/Support/FormatVariadic.h"
Mitch Phillipsc15bdf52017-11-03 20:54:26 +000026#include "llvm/Support/SpecialCaseList.h"
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000027
Vlad Tsyrklevich31b45312017-09-20 20:38:14 +000028#include <cstdlib>
29
30using namespace llvm;
31using namespace llvm::object;
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000032using namespace llvm::cfi_verify;
Vlad Tsyrklevich31b45312017-09-20 20:38:14 +000033
Vlad Tsyrklevich31b45312017-09-20 20:38:14 +000034cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input file>"),
35 cl::Required);
Mitch Phillipsc15bdf52017-11-03 20:54:26 +000036cl::opt<std::string> BlacklistFilename(cl::Positional,
37 cl::desc("[blacklist file]"),
38 cl::init("-"));
Vlad Tsyrklevich31b45312017-09-20 20:38:14 +000039
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000040ExitOnError ExitOnErr;
Vlad Tsyrklevich31b45312017-09-20 20:38:14 +000041
Mitch Phillipsc15bdf52017-11-03 20:54:26 +000042void printIndirectCFInstructions(FileAnalysis &Analysis,
43 const SpecialCaseList *SpecialCaseList) {
44 uint64_t ExpectedProtected = 0;
45 uint64_t UnexpectedProtected = 0;
46 uint64_t ExpectedUnprotected = 0;
47 uint64_t UnexpectedUnprotected = 0;
48
49 symbolize::LLVMSymbolizer &Symbolizer = Analysis.getSymbolizer();
Mitch Phillipsd64af522017-11-09 00:18:31 +000050 std::map<unsigned, uint64_t> BlameCounter;
Mitch Phillips7db6f7a2017-10-31 23:20:05 +000051
52 for (uint64_t Address : Analysis.getIndirectInstructions()) {
53 const auto &InstrMeta = Analysis.getInstructionOrDie(Address);
54
Mitch Phillipsc15bdf52017-11-03 20:54:26 +000055 bool CFIProtected = Analysis.isIndirectInstructionCFIProtected(Address);
56
57 if (CFIProtected)
Mitch Phillips7db6f7a2017-10-31 23:20:05 +000058 outs() << "P ";
Mitch Phillipsc15bdf52017-11-03 20:54:26 +000059 else
Mitch Phillips7db6f7a2017-10-31 23:20:05 +000060 outs() << "U ";
Mitch Phillips7db6f7a2017-10-31 23:20:05 +000061
62 outs() << format_hex(Address, 2) << " | "
63 << Analysis.getMCInstrInfo()->getName(
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000064 InstrMeta.Instruction.getOpcode())
Mitch Phillipsc15bdf52017-11-03 20:54:26 +000065 << " \n";
Mitch Phillips7db6f7a2017-10-31 23:20:05 +000066
Mitch Phillipsc15bdf52017-11-03 20:54:26 +000067 if (IgnoreDWARFFlag) {
68 if (CFIProtected)
69 ExpectedProtected++;
70 else
71 UnexpectedUnprotected++;
72 continue;
73 }
74
75 auto InliningInfo = Symbolizer.symbolizeInlinedCode(InputFilename, Address);
76 if (!InliningInfo || InliningInfo->getNumberOfFrames() == 0) {
77 errs() << "Failed to symbolise " << format_hex(Address, 2)
78 << " with line tables from " << InputFilename << "\n";
79 exit(EXIT_FAILURE);
80 }
81
82 const auto &LineInfo =
83 InliningInfo->getFrame(InliningInfo->getNumberOfFrames() - 1);
84
85 // Print the inlining symbolisation of this instruction.
86 for (uint32_t i = 0; i < InliningInfo->getNumberOfFrames(); ++i) {
87 const auto &Line = InliningInfo->getFrame(i);
88 outs() << " " << format_hex(Address, 2) << " = " << Line.FileName << ":"
89 << Line.Line << ":" << Line.Column << " (" << Line.FunctionName
90 << ")\n";
91 }
92
93 if (!SpecialCaseList) {
94 if (CFIProtected)
95 ExpectedProtected++;
96 else
97 UnexpectedUnprotected++;
98 continue;
99 }
100
Mitch Phillipsd64af522017-11-09 00:18:31 +0000101 unsigned BlameLine = 0;
102 for (auto &K : {"cfi-icall", "cfi-vcall"}) {
103 if (!BlameLine)
104 BlameLine =
105 SpecialCaseList->inSectionBlame(K, "src", LineInfo.FileName);
106 if (!BlameLine)
107 BlameLine =
108 SpecialCaseList->inSectionBlame(K, "fun", LineInfo.FunctionName);
Mitch Phillipsc15bdf52017-11-03 20:54:26 +0000109 }
110
Mitch Phillipsd64af522017-11-09 00:18:31 +0000111 if (BlameLine) {
112 outs() << "Blacklist Match: " << BlacklistFilename << ":" << BlameLine
113 << "\n";
114 BlameCounter[BlameLine]++;
Mitch Phillipsc15bdf52017-11-03 20:54:26 +0000115 if (CFIProtected) {
116 UnexpectedProtected++;
117 outs() << "====> Unexpected Protected\n";
118 } else {
119 ExpectedUnprotected++;
120 outs() << "====> Expected Unprotected\n";
121 }
122 } else {
123 if (CFIProtected) {
124 ExpectedProtected++;
125 outs() << "====> Expected Protected\n";
126 } else {
127 UnexpectedUnprotected++;
128 outs() << "====> Unexpected Unprotected\n";
Mitch Phillips7db6f7a2017-10-31 23:20:05 +0000129 }
130 }
Vlad Tsyrklevich31b45312017-09-20 20:38:14 +0000131 }
Mitch Phillips7db6f7a2017-10-31 23:20:05 +0000132
Mitch Phillipsc15bdf52017-11-03 20:54:26 +0000133 uint64_t IndirectCFInstructions = ExpectedProtected + UnexpectedProtected +
134 ExpectedUnprotected + UnexpectedUnprotected;
135
Mitch Phillips6fb35252017-11-06 19:14:09 +0000136 if (IndirectCFInstructions == 0) {
Mitch Phillips7db6f7a2017-10-31 23:20:05 +0000137 outs() << "No indirect CF instructions found.\n";
Mitch Phillips6fb35252017-11-06 19:14:09 +0000138 return;
139 }
Mitch Phillipsc15bdf52017-11-03 20:54:26 +0000140
141 outs() << formatv("Expected Protected: {0} ({1:P})\n"
142 "Unexpected Protected: {2} ({3:P})\n"
143 "Expected Unprotected: {4} ({5:P})\n"
144 "Unexpected Unprotected (BAD): {6} ({7:P})\n",
145 ExpectedProtected,
146 ((double)ExpectedProtected) / IndirectCFInstructions,
147 UnexpectedProtected,
148 ((double)UnexpectedProtected) / IndirectCFInstructions,
149 ExpectedUnprotected,
150 ((double)ExpectedUnprotected) / IndirectCFInstructions,
151 UnexpectedUnprotected,
152 ((double)UnexpectedUnprotected) / IndirectCFInstructions);
Mitch Phillipsd64af522017-11-09 00:18:31 +0000153
154 if (!SpecialCaseList)
155 return;
156
157 outs() << "Blacklist Results:\n";
158 for (const auto &KV : BlameCounter) {
159 outs() << " " << BlacklistFilename << ":" << KV.first << " affects "
160 << KV.second << " indirect CF instructions.\n";
161 }
Vlad Tsyrklevich31b45312017-09-20 20:38:14 +0000162}
163
164int main(int argc, char **argv) {
Mitch Phillips7db6f7a2017-10-31 23:20:05 +0000165 cl::ParseCommandLineOptions(
166 argc, argv,
167 "Identifies whether Control Flow Integrity protects all indirect control "
168 "flow instructions in the provided object file, DSO or binary.\nNote: "
169 "Anything statically linked into the provided file *must* be compiled "
170 "with '-g'. This can be relaxed through the '--ignore-dwarf' flag.");
Vlad Tsyrklevich31b45312017-09-20 20:38:14 +0000171
172 InitializeAllTargetInfos();
173 InitializeAllTargetMCs();
174 InitializeAllAsmParsers();
175 InitializeAllDisassemblers();
176
Mitch Phillipsc15bdf52017-11-03 20:54:26 +0000177 std::unique_ptr<SpecialCaseList> SpecialCaseList;
178 if (BlacklistFilename != "-") {
179 std::string Error;
180 SpecialCaseList = SpecialCaseList::create({BlacklistFilename}, Error);
181 if (!SpecialCaseList) {
182 errs() << "Failed to get blacklist: " << Error << "\n";
183 exit(EXIT_FAILURE);
184 }
185 }
186
Mitch Phillips7db6f7a2017-10-31 23:20:05 +0000187 FileAnalysis Analysis = ExitOnErr(FileAnalysis::Create(InputFilename));
Mitch Phillipsc15bdf52017-11-03 20:54:26 +0000188 printIndirectCFInstructions(Analysis, SpecialCaseList.get());
Vlad Tsyrklevich31b45312017-09-20 20:38:14 +0000189
190 return EXIT_SUCCESS;
191}