Add Forward Control-Flow Integrity.

This commit adds a new pass that can inject checks before indirect calls to
make sure that these calls target known locations. It supports three types of
checks and, at compile time, it can take the name of a custom function to call
when an indirect call check fails. The default failure function ignores the
error and continues.

This pass incidentally moves the function JumpInstrTables::transformType from
private to public and makes it static (with a new argument that specifies the
table type to use); this is so that the CFI code can transform function types
at call sites to determine which jump-instruction table to use for the check at
that site.

Also, this removes support for jumptables in ARM, pending further performance
analysis and discussion.

Review: http://reviews.llvm.org/D4167



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@221708 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Tom Roeder
2014-11-11 21:08:02 +00:00
parent 6d093fd78a
commit 63dea2c952
29 changed files with 873 additions and 133 deletions

View File

@@ -222,6 +222,44 @@ JTableType("jump-table-type",
"Create one table per unique function type."),
clEnumValEnd));
cl::opt<bool>
FCFI("fcfi",
cl::desc("Apply forward-edge control-flow integrity"),
cl::init(false));
cl::opt<llvm::CFIntegrity>
CFIType("cfi-type",
cl::desc("Choose the type of Control-Flow Integrity check to add"),
cl::init(CFIntegrity::Sub),
cl::values(
clEnumValN(CFIntegrity::Sub, "sub",
"Subtract the pointer from the table base, then mask."),
clEnumValN(CFIntegrity::Ror, "ror",
"Use rotate to check the offset from a table base."),
clEnumValN(CFIntegrity::Add, "add",
"Mask out the high bits and add to an aligned base."),
clEnumValEnd));
cl::opt<bool>
CFIEnforcing("cfi-enforcing",
cl::desc("Enforce CFI or pass the violation to a function."),
cl::init(false));
// Note that this option is linked to the cfi-enforcing option above: if
// cfi-enforcing is set, then the cfi-func-name option is entirely ignored. If
// cfi-enforcing is false and no cfi-func-name is set, then a default function
// will be generated that ignores all CFI violations. The expected signature for
// functions called with CFI violations is
//
// void (i8*, i8*)
//
// The first pointer is a C string containing the name of the function in which
// the violation occurs, and the second pointer is the pointer that violated
// CFI.
cl::opt<std::string>
CFIFuncName("cfi-func-name", cl::desc("The name of the CFI function to call"),
cl::init(""));
// Common utility function tightly tied to the options listed here. Initializes
// a TargetOptions object with CodeGen flags and returns it.
static inline TargetOptions InitTargetOptionsFromCodeGenFlags() {
@@ -249,6 +287,10 @@ static inline TargetOptions InitTargetOptionsFromCodeGenFlags() {
Options.MCOptions = InitMCTargetOptionsFromFlags();
Options.JTType = JTableType;
Options.FCFI = FCFI;
Options.CFIType = CFIType;
Options.CFIEnforcing = CFIEnforcing;
Options.CFIFuncName = CFIFuncName;
Options.ThreadModel = TMModel;