8000 Add Windows Control Flow Guard checks (/guard:cf). · llvm/llvm-project@d157a9b · GitHub
[go: up one dir, main page]

Skip to content

Commit d157a9b

Browse files
ajpaverddavidchisnall
authored andcommitted
Add Windows Control Flow Guard checks (/guard:cf).
Summary: A new function pass (Transforms/CFGuard/CFGuard.cpp) inserts CFGuard checks on indirect function calls, using either the check mechanism (X86, ARM, AArch64) or or the dispatch mechanism (X86-64). The check mechanism requires a new calling convention for the supported targets. The dispatch mechanism adds the target as an operand bundle, which is processed by SelectionDAG. Another pass (CodeGen/CFGuardLongjmp.cpp) identifies and emits valid longjmp targets, as required by /guard:cf. This feature is enabled using the `cfguard` CC1 option. Reviewers: thakis, rnk, theraven, pcc Subscribers: ychen, hans, metalcanine, dmajor, tomrittervg, alex, mehdi_amini, mgorny, javed.absar, kristof.beyls, hiraditya, steven_wu, dexonsmith, cfe-commits, llvm-commits Tags: #clang, #llvm Differential Revision: https://reviews.llvm.org/D65761
1 parent a233e7d commit d157a9b

File tree

77 files changed

+1514
-62
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+1514
-62
lines changed

clang/docs/ClangCommandLineReference.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,11 @@ Output path for the plist report
124124

125125
.. option:: -cfguard
126126

127-
Emit tables required for Windows Control Flow Guard.
127+
Emit tables and checks for Windows Control Flow Guard.
128+
129+
.. option:: -cfguard-no-checks
130+
131+
Emit tables required for Windows Control Flow Guard without checks.
128132

129133
.. option:: -client\_name<arg>
130134

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ CODEGENOPT(AssumeSaneOperatorNew , 1, 1) ///< implicit __attribute__((malloc)) o
3737
CODEGENOPT(Autolink , 1, 1) ///< -fno-autolink
3838
CODEGENOPT(ObjCAutoRefCountExceptions , 1, 0) ///< Whether ARC should be EH-safe.
3939
CODEGENOPT(Backchain , 1, 0) ///< -mbackchain
40+
CODEGENOPT(ControlFlowGuardNoChecks , 1, 0) ///< -cfguard-no-checks
4041
CODEGENOPT(ControlFlowGuard , 1, 0) ///< -cfguard
4142
CODEGENOPT(CoverageExtraChecksum, 1, 0) ///< Whether we need a second checksum for functions in GCNO files.
4243
CODEGENOPT(CoverageNoFunctionNamesInData, 1, 0) ///< Do not include function names in GCDA files.

clang/include/clang/Driver/CC1Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,10 @@ def msign_return_address_key_EQ : Joined<["-"], "msign-return-address-key=">,
400400
Values<"a_key,b_key">;
401401
def mbranch_target_enforce : Flag<["-"], "mbranch-target-enforce">;
402402
def fno_dllexport_inlines : Flag<["-"], "fno-dllexport-inlines">;
403+
def cfguard_no_checks : Flag<["-"], "cfguard-no-checks">,
404+
HelpText<"Emit Windows Control Flow Guard tables only (no checks)">;
405+
def cfguard : Flag<["-"], "cfguard">,
406+
HelpText<"Emit Windows Control Flow Guard tables and checks">;
403407

404408
//===----------------------------------------------------------------------===//
405409
// Dependency Output Options

clang/include/clang/Driver/Options.td

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -503,8 +503,6 @@ def bind__at__load : Flag<["-"], "bind_at_load">;
503503
def bundle__loader : Separate<["-"], "bundle_loader">;
504504
def bundle : Flag<["-"], "bundle">;
505505
def b : JoinedOrSeparate<["-"], "b">, Flags<[Unsupported]>;
506-
def cfguard : Flag<["-"], "cfguard">, Flags<[CC1Option]>,
507-
HelpText<"Emit tables required for Windows Control Flow Guard.">;
508506
def cl_opt_disable : Flag<["-"], "cl-opt-disable">, Group<opencl_Group>, Flags<[CC1Option]>,
509507
HelpText<"OpenCL only. This option disables all optimizations. By default optimizations are enabled.">;
510508
def cl_strict_aliasing : Flag<["-"], "cl-strict-aliasing">, Group<opencl_Group>, Flags<[CC1Option]>,

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,8 +482,11 @@ void CodeGenModule::Release() {
482482
getModule().addModuleFlag(llvm::Module::Warning, "CodeViewGHash", 1);
483483
}
484484
if (CodeGenOpts.ControlFlowGuard) {
485-
// We want function ID tables for Control Flow Guard.
486-
getModule().addModuleFlag(llvm::Module::Warning, "cfguardtable", 1);
485+
// Function ID tables and checks for Control Flow Guard (cfguard=2).
486+
getModule().addModuleFlag(llvm::Module::Warning, "cfguard", 2);
487+
} else if (CodeGenOpts.ControlFlowGuardNoChecks) {
488+
// Function ID tables for Control Flow Guard (cfguard=1).
489+
getModule().addModuleFlag(llvm::Module::Warning, "cfguard", 1);
487490
}
488491
if (CodeGenOpts.OptimizationLevel > 0 && CodeGenOpts.StrictVTablePointers) {
489492
// We don't support LTO with 2 with different StrictVTablePointers

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5975,26 +5975,19 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
59755975
}
59765976

59775977
if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) {
5978-
SmallVector<StringRef, 1> SplitArgs;
5979-
StringRef(A->getValue()).split(SplitArgs, ",");
5980-
bool Instrument = false;
5981-
bool NoChecks = false;
5982-
for (StringRef Arg : SplitArgs) {
5983-
if (Arg.equals_lower("cf"))
5984-
Instrument = true;
5985-
else if (Arg.equals_lower("cf-"))
5986-
Instrument = false;
5987-
else if (Arg.equals_lower("nochecks"))
5988-
NoChecks = true;
5989-
else if (Arg.equals_lower("nochecks-"))
5990-
NoChecks = false;
5991-
else
5992-
D.Diag(diag::err_drv_invalid_value) << A->getSpelling() << Arg;
5993-
}
5994-
// Currently there's no support emitting CFG instrumentation; the flag only
5995-
// emits the table of address-taken functions.
5996-
if (Instrument || NoChecks)
5978+
StringRef GuardArgs = A->getValue();
5979+
// The only valid options are "cf", "cf,nochecks", and "cf-".
5980+
if (GuardArgs.equals_lower("cf")) {
5981+
// Emit CFG instrumentation and the table of address-taken functions.
59975982
CmdArgs.push_back("-cfguard");
5983+
} else if (GuardArgs.equals_lower("cf,nochecks")) {
5984+
// Emit only the table of address-taken functions.
5985+
CmdArgs.push_back("-cfguard-no-checks");
5986+
} else if (GuardArgs.equals_lower("cf-")) {
5987+
// Do nothing, but we might want to emit a security warning in future.
5988+
} else {
5989+
D.Diag(diag::err_drv_invalid_value) << A->getSpelling() << GuardArgs;
5990+
}
59985991
}
59995992
}
60005993

clang/lib/Driver/ToolChains/MSVC.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,17 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
422422

423423
Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
424424

425+
// Control Flow Guard checks
426+
if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) {
427+
StringRef GuardArgs = A->getValue();
428+
if (GuardArgs.equals_lower("cf") || GuardArgs.equals_lower("cf,nochecks")) {
429+
// MSVC doesn't yet support the "nochecks" modifier.
430+
CmdArgs.push_back("-guard:cf");
431+
} else if (GuardArgs.equals_lower("cf-")) {
432+
CmdArgs.push_back("-guard:cf-");
433+
}
434+
}
435+
425436
if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
426437
options::OPT_fno_openmp, false)) {
427438
CmdArgs.push_back("-nodefaultlib:vcomp.lib");
@@ -679,6 +690,17 @@ std::unique_ptr<Command> visualstudio::Compiler::GetCommand(
679690
: "/Zc:threadSafeInit-");
680691
}
681692

693+
// Control Flow Guard checks
694+
if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) {
695+
StringRef GuardArgs = A->getValue();
696+
if (GuardArgs.equals_lower("cf") || GuardArgs.equals_lower("cf,nochecks")) {
697+
// MSVC doesn't yet support the "nochecks" modifier.
698+
CmdArgs.push_back("/guard:cf");
699+
} else if (GuardArgs.equals_lower("cf-")) {
700+
CmdArgs.push_back("/guard:cf-");
701+
}
702+
}
703+
682704
// Pass through all unknown arguments so that the fallback command can see
683705
// them too.
684706
Args.AddAllArgs(CmdArgs, options::OPT_UNKNOWN);

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
10031003
Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name);
10041004
Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
10051005

1006+
Opts.ControlFlowGuardNoChecks = Args.hasArg(OPT_cfguard_no_checks);
10061007
Opts.ControlFlowGuard = Args.hasArg(OPT_cfguard);
10071008

10081009
Opts.DisableGCov = Args.hasArg(OPT_test_coverage);

clang/test/CodeGen/cfguardtable.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
// RUN: %clang_cc1 -cfguard -emit-llvm %s -o - | FileCheck %s
2-
3-
void f() {}
4-
5-
// Check that the cfguardtable metadata flag gets set on the module.
6-
// CHECK: !"cfguardtable", i32 1}
1+
// RUN: %clang_cc1 -cfguard-no-checks -emit-llvm %s -o - | FileCheck %s -check-prefix=CFGUARDNOCHECKS
2+
// RUN: %clang_cc1 -cfguard -emit-llvm %s -o - | FileCheck %s -check-prefix=CFGUARD
3+
4+
void f() {}
5+
6+
// Check that the cfguard metadata flag gets correctly set on the module.
7+
// CFGUARDNOCHECKS: !"cfguard", i32 1}
8+
// CFGUARD: !"cfguard", i32 2}

clang/test/Driver/cl-fallback.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// command-line option, e.g. on Mac where %s is commonly under /Users.
33

44
// RUN: %clang_cl --target=i686-pc-win32 /fallback /Dfoo=bar /Ubaz /Ifoo /O0 /Ox /GR /GR- /GS /GS- /Gy /Gy- \
5-
// RUN: /Gw /Gw- /LD /LDd /EHs /EHs- /Zl /MD /MDd /MTd /MT /FImyheader.h /Zi \
5+
// RUN: /Gw /Gw- /LD /LDd /EHs /EHs- /Zl /MD /MDd /MTd /MT /guard:cf /guard:cf- /FImyheader.h /Zi \
66
// RUN: -garbage -moregarbage \
77
// RUN: -### -- %s 2>&1 \
88
// RUN: | FileCheck %s
@@ -33,6 +33,7 @@
3333
// CHECK: "/EHs-"
3434
// CHECK: "/Zl"
3535
// CHECK: "/MT"
36+
// CHECK: "/guard:cf-"
3637
// CHECK: "-garbage"
3738
// CHECK: "-moregarbage"
3839
// CHECK: "/Tc" "{{.*cl-fallback.c}}"

0 commit comments

Comments
 (0)
0