aboutsummaryrefslogtreecommitdiff
path: root/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
blob: d4a46fcc226b6529e26de326216cacb60e39ad66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//===-- 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 <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);

ExitOnError ExitOnErr;

void printIndirectCFInstructions(FileAnalysis &Analysis) {
  uint64_t ProtectedCount = 0;
  uint64_t UnprotectedCount = 0;

  for (uint64_t Address : Analysis.getIndirectInstructions()) {
    const auto &InstrMeta = Analysis.getInstructionOrDie(Address);

    if (Analysis.isIndirectInstructionCFIProtected(Address)) {
      outs() << "P ";
      ProtectedCount++;
    } else {
      outs() << "U ";
      UnprotectedCount++;
    }

    outs() << format_hex(Address, 2) << " | "
           << Analysis.getMCInstrInfo()->getName(
                  InstrMeta.Instruction.getOpcode())
           << " ";
    outs() << "\n";

    if (Analysis.hasLineTableInfo()) {
      for (const auto &LineKV : Analysis.getLineInfoForAddressRange(Address)) {
        outs() << "  " << format_hex(LineKV.first, 2) << " = "
               << LineKV.second.FileName << ":" << LineKV.second.Line << ":"
               << LineKV.second.Column << " (" << LineKV.second.FunctionName
               << ")\n";
      }
    }
  }

  if (ProtectedCount || UnprotectedCount)
    outs() << formatv(
        "Unprotected: {0} ({1:P}), Protected: {2} ({3:P})\n", UnprotectedCount,
        (((double)UnprotectedCount) / (UnprotectedCount + ProtectedCount)),
        ProtectedCount,
        (((double)ProtectedCount) / (UnprotectedCount + ProtectedCount)));
  else
    outs() << "No indirect CF instructions found.\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();

  FileAnalysis Analysis = ExitOnErr(FileAnalysis::Create(InputFilename));
  printIndirectCFInstructions(Analysis);

  return EXIT_SUCCESS;
}