mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 12:43:36 +01:00
4e04076e39
Adds the blacklist behaviour to llvm-cfi-verify. Now will calculate which lines caused expected failures in the blacklist and reports the number of affected indirect CF instructions for each blacklist entry. Also moved DWARF checking after instruction analysis to improve performance significantly - unrolling the inlining stack is expensive. Reviewers: vlad.tsyrklevich Subscribers: aprantl, pcc, kcc, llvm-commits Differential Revision: https://reviews.llvm.org/D39750 llvm-svn: 317743
192 lines
6.4 KiB
C++
192 lines
6.4 KiB
C++
//===-- llvm-cfi-verify.cpp - CFI Verification tool for LLVM --------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This tool verifies Control Flow Integrity (CFI) instrumentation by static
|
|
// binary anaylsis. See the design document in /docs/CFIVerify.rst for more
|
|
// information.
|
|
//
|
|
// This tool is currently incomplete. It currently only does disassembly for
|
|
// object files, and searches through the code for indirect control flow
|
|
// instructions, printing them once found.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lib/FileAnalysis.h"
|
|
|
|
#include "llvm/BinaryFormat/ELF.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/FormatVariadic.h"
|
|
#include "llvm/Support/SpecialCaseList.h"
|
|
|
|
#include <cstdlib>
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::object;
|
|
using namespace llvm::cfi_verify;
|
|
|
|
cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input file>"),
|
|
cl::Required);
|
|
cl::opt<std::string> BlacklistFilename(cl::Positional,
|
|
cl::desc("[blacklist file]"),
|
|
cl::init("-"));
|
|
|
|
ExitOnError ExitOnErr;
|
|
|
|
void printIndirectCFInstructions(FileAnalysis &Analysis,
|
|
const SpecialCaseList *SpecialCaseList) {
|
|
uint64_t ExpectedProtected = 0;
|
|
uint64_t UnexpectedProtected = 0;
|
|
uint64_t ExpectedUnprotected = 0;
|
|
uint64_t UnexpectedUnprotected = 0;
|
|
|
|
symbolize::LLVMSymbolizer &Symbolizer = Analysis.getSymbolizer();
|
|
std::map<unsigned, uint64_t> BlameCounter;
|
|
|
|
for (uint64_t Address : Analysis.getIndirectInstructions()) {
|
|
const auto &InstrMeta = Analysis.getInstructionOrDie(Address);
|
|
|
|
bool CFIProtected = Analysis.isIndirectInstructionCFIProtected(Address);
|
|
|
|
if (CFIProtected)
|
|
outs() << "P ";
|
|
else
|
|
outs() << "U ";
|
|
|
|
outs() << format_hex(Address, 2) << " | "
|
|
<< Analysis.getMCInstrInfo()->getName(
|
|
InstrMeta.Instruction.getOpcode())
|
|
<< " \n";
|
|
|
|
if (IgnoreDWARFFlag) {
|
|
if (CFIProtected)
|
|
ExpectedProtected++;
|
|
else
|
|
UnexpectedUnprotected++;
|
|
continue;
|
|
}
|
|
|
|
auto InliningInfo = Symbolizer.symbolizeInlinedCode(InputFilename, Address);
|
|
if (!InliningInfo || InliningInfo->getNumberOfFrames() == 0) {
|
|
errs() << "Failed to symbolise " << format_hex(Address, 2)
|
|
<< " with line tables from " << InputFilename << "\n";
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
const auto &LineInfo =
|
|
InliningInfo->getFrame(InliningInfo->getNumberOfFrames() - 1);
|
|
|
|
// Print the inlining symbolisation of this instruction.
|
|
for (uint32_t i = 0; i < InliningInfo->getNumberOfFrames(); ++i) {
|
|
const auto &Line = InliningInfo->getFrame(i);
|
|
outs() << " " << format_hex(Address, 2) << " = " << Line.FileName << ":"
|
|
<< Line.Line << ":" << Line.Column << " (" << Line.FunctionName
|
|
<< ")\n";
|
|
}
|
|
|
|
if (!SpecialCaseList) {
|
|
if (CFIProtected)
|
|
ExpectedProtected++;
|
|
else
|
|
UnexpectedUnprotected++;
|
|
continue;
|
|
}
|
|
|
|
unsigned BlameLine = 0;
|
|
for (auto &K : {"cfi-icall", "cfi-vcall"}) {
|
|
if (!BlameLine)
|
|
BlameLine =
|
|
SpecialCaseList->inSectionBlame(K, "src", LineInfo.FileName);
|
|
if (!BlameLine)
|
|
BlameLine =
|
|
SpecialCaseList->inSectionBlame(K, "fun", LineInfo.FunctionName);
|
|
}
|
|
|
|
if (BlameLine) {
|
|
outs() << "Blacklist Match: " << BlacklistFilename << ":" << BlameLine
|
|
<< "\n";
|
|
BlameCounter[BlameLine]++;
|
|
if (CFIProtected) {
|
|
UnexpectedProtected++;
|
|
outs() << "====> Unexpected Protected\n";
|
|
} else {
|
|
ExpectedUnprotected++;
|
|
outs() << "====> Expected Unprotected\n";
|
|
}
|
|
} else {
|
|
if (CFIProtected) {
|
|
ExpectedProtected++;
|
|
outs() << "====> Expected Protected\n";
|
|
} else {
|
|
UnexpectedUnprotected++;
|
|
outs() << "====> Unexpected Unprotected\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
uint64_t IndirectCFInstructions = ExpectedProtected + UnexpectedProtected +
|
|
ExpectedUnprotected + UnexpectedUnprotected;
|
|
|
|
if (IndirectCFInstructions == 0) {
|
|
outs() << "No indirect CF instructions found.\n";
|
|
return;
|
|
}
|
|
|
|
outs() << formatv("Expected Protected: {0} ({1:P})\n"
|
|
"Unexpected Protected: {2} ({3:P})\n"
|
|
"Expected Unprotected: {4} ({5:P})\n"
|
|
"Unexpected Unprotected (BAD): {6} ({7:P})\n",
|
|
ExpectedProtected,
|
|
((double)ExpectedProtected) / IndirectCFInstructions,
|
|
UnexpectedProtected,
|
|
((double)UnexpectedProtected) / IndirectCFInstructions,
|
|
ExpectedUnprotected,
|
|
((double)ExpectedUnprotected) / IndirectCFInstructions,
|
|
UnexpectedUnprotected,
|
|
((double)UnexpectedUnprotected) / IndirectCFInstructions);
|
|
|
|
if (!SpecialCaseList)
|
|
return;
|
|
|
|
outs() << "Blacklist Results:\n";
|
|
for (const auto &KV : BlameCounter) {
|
|
outs() << " " << BlacklistFilename << ":" << KV.first << " affects "
|
|
<< KV.second << " indirect CF instructions.\n";
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
cl::ParseCommandLineOptions(
|
|
argc, argv,
|
|
"Identifies whether Control Flow Integrity protects all indirect control "
|
|
"flow instructions in the provided object file, DSO or binary.\nNote: "
|
|
"Anything statically linked into the provided file *must* be compiled "
|
|
"with '-g'. This can be relaxed through the '--ignore-dwarf' flag.");
|
|
|
|
InitializeAllTargetInfos();
|
|
InitializeAllTargetMCs();
|
|
InitializeAllAsmParsers();
|
|
InitializeAllDisassemblers();
|
|
|
|
std::unique_ptr<SpecialCaseList> SpecialCaseList;
|
|
if (BlacklistFilename != "-") {
|
|
std::string Error;
|
|
SpecialCaseList = SpecialCaseList::create({BlacklistFilename}, Error);
|
|
if (!SpecialCaseList) {
|
|
errs() << "Failed to get blacklist: " << Error << "\n";
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
FileAnalysis Analysis = ExitOnErr(FileAnalysis::Create(InputFilename));
|
|
printIndirectCFInstructions(Analysis, SpecialCaseList.get());
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|