From: Oren Ben Simhon Date: Tue, 9 Jan 2018 08:53:59 +0000 (+0000) Subject: Added Control Flow Protection Flag X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1955fd01bdd56c691bb71410251faaa7feb66f81;p=clang Added Control Flow Protection Flag Cf-protection is a target independent flag that instructs the back-end to instrument control flow mechanisms like: Branch, Return, etc. For example in X86 this flag will be used to instrument Indirect Branch Tracking instructions. Differential Revision: https://reviews.llvm.org/D40478 Change-Id: I5126e766c0e6b84118cae0ee8a20fe78cc373dea git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@322063 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index 711204a790..33e9867a8f 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -203,6 +203,8 @@ def err_target_unsupported_execute_only : Error< "execute only is not supported for the %0 sub-architecture">; def err_opt_not_valid_with_opt : Error< "option '%0' cannot be specified with '%1'">; +def err_opt_not_valid_without_opt : Error< + "option '%0' cannot be specified without '%1'">; // Source manager def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal; diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index fad923c272..0fc622348c 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -1051,6 +1051,18 @@ public: return false; } + /// Check if the target supports CFProtection branch. + virtual bool + checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const { + return false; + } + + /// Check if the target supports CFProtection branch. + virtual bool + checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const { + return false; + } + /// \brief Whether target allows to overalign ABI-specified preferred alignment virtual bool allowsLargerPreferedTypeAlignment() const { return true; } diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index d84613c059..af4ea3e3e6 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -1042,6 +1042,11 @@ def finstrument_functions_after_inlining : Flag<["-"], "finstrument-functions-af HelpText<"Like -finstrument-functions, but insert the calls after inlining">; def finstrument_function_entry_bare : Flag<["-"], "finstrument-function-entry-bare">, Group, Flags<[CC1Option]>, HelpText<"Instrument function entry only, after inlining, without arguments to the instrumentation call">; +def fcf_protection_EQ : Joined<["-"], "fcf-protection=">, Flags<[CoreOption, CC1Option]>, Group, + HelpText<"Instrument control-flow architecture protection. Options: return, branch, full, none.">, Values<"return,branch,full,none">; +def fcf_protection : Flag<["-"], "fcf-protection">, Group, Flags<[CoreOption, CC1Option]>, + Alias, AliasArgs<["full"]>, + HelpText<"Enable cf-protection in 'full' mode">; def fxray_instrument : Flag<["-"], "fxray-instrument">, Group, Flags<[CC1Option]>, diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def index 0ee3bb1197..7948459934 100644 --- a/include/clang/Frontend/CodeGenOptions.def +++ b/include/clang/Frontend/CodeGenOptions.def @@ -80,7 +80,10 @@ CODEGENOPT(InstrumentFunctionsAfterInlining , 1, 0) ///< Set when ///< -finstrument-functions-after-inlining is enabled. CODEGENOPT(InstrumentFunctionEntryBare , 1, 0) ///< Set when ///< -finstrument-function-entry-bare is enabled. - +CODEGENOPT(CFProtectionReturn , 1, 0) ///< if -fcf-protection is + ///< set to full or return. +CODEGENOPT(CFProtectionBranch , 1, 0) ///< if -fcf-protection is + ///< set to full or branch. CODEGENOPT(XRayInstrumentFunctions , 1, 0) ///< Set when -fxray-instrument is ///< enabled. CODEGENOPT(StackSizeSection , 1, 0) ///< Set when -fstack-size-section is enabled. diff --git a/lib/Basic/Targets/X86.cpp b/lib/Basic/Targets/X86.cpp index 5d4dfcb844..268b359011 100644 --- a/lib/Basic/Targets/X86.cpp +++ b/lib/Basic/Targets/X86.cpp @@ -101,6 +101,26 @@ bool X86TargetInfo::setFPMath(StringRef Name) { return false; } +bool X86TargetInfo::checkCFProtectionReturnSupported( + DiagnosticsEngine &Diags) const { + if (HasSHSTK) + return true; + + Diags.Report(diag::err_opt_not_valid_without_opt) << "cf-protection=return" + << "-mshstk"; + return false; +} + +bool X86TargetInfo::checkCFProtectionBranchSupported( + DiagnosticsEngine &Diags) const { + if (HasIBT) + return true; + + Diags.Report(diag::err_opt_not_valid_without_opt) << "cf-protection=branch" + << "-mibt"; + return false; +} + bool X86TargetInfo::initFeatureMap( llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const { diff --git a/lib/Basic/Targets/X86.h b/lib/Basic/Targets/X86.h index 58b7a09c9a..290d3db350 100644 --- a/lib/Basic/Targets/X86.h +++ b/lib/Basic/Targets/X86.h @@ -158,6 +158,12 @@ public: bool validateInputSize(StringRef Constraint, unsigned Size) const override; + virtual bool + checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const override; + + virtual bool + checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const override; + virtual bool validateOperandSize(StringRef Constraint, unsigned Size) const; std::string convertConstraint(const char *&Constraint) const override; diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 0cbe071d1b..4a45b5ac19 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -887,7 +887,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, } // Apply xray attributes to the function (as a string, for now) - if (D && ShouldXRayInstrumentFunction()) { + bool InstrumentXray = ShouldXRayInstrumentFunction(); + if (D && InstrumentXray) { if (const auto *XRayAttr = D->getAttr()) { if (XRayAttr->alwaysXRayInstrument()) Fn->addFnAttr("function-instrument", "xray-always"); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 32c9b28124..b08ead80c1 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -502,6 +502,20 @@ void CodeGenModule::Release() { getModule().addModuleFlag(llvm::Module::Override, "Cross-DSO CFI", 1); } + if (CodeGenOpts.CFProtectionReturn && + Target.checkCFProtectionReturnSupported(getDiags())) { + // Indicate that we want to instrument return control flow protection. + getModule().addModuleFlag(llvm::Module::Override, "cf-protection-return", + 1); + } + + if (CodeGenOpts.CFProtectionBranch && + Target.checkCFProtectionBranchSupported(getDiags())) { + // Indicate that we want to instrument branch control flow protection. + getModule().addModuleFlag(llvm::Module::Override, "cf-protection-branch", + 1); + } + if (LangOpts.CUDAIsDevice && getTriple().isNVPTX()) { // Indicate whether __nvvm_reflect should be configured to flush denormal // floating point values to 0. (This corresponds to its "__CUDA_FTZ" diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index b7241d2f6b..2db660dc2b 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -4008,6 +4008,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Forward -cl options to -cc1 RenderOpenCLOptions(Args, CmdArgs); + if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) { + CmdArgs.push_back( + Args.MakeArgString(Twine("-fcf-protection=") + A->getValue())); + } + // Forward -f options with positive and negative forms; we translate // these by hand. if (Arg *A = getLastProfileSampleUseArg(Args)) { diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 2252800468..7af58b1794 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -798,6 +798,21 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.CallFEntry = Args.hasArg(OPT_mfentry); Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info); + if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) { + StringRef Name = A->getValue(); + if (Name == "full") { + Opts.CFProtectionReturn = 1; + Opts.CFProtectionBranch = 1; + } else if (Name == "return") + Opts.CFProtectionReturn = 1; + else if (Name == "branch") + Opts.CFProtectionBranch = 1; + else if (Name != "none") { + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; + Success = false; + } + } + if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections, OPT_compress_debug_sections_EQ)) { if (A->getOption().getID() == OPT_compress_debug_sections) { diff --git a/test/CodeGen/x86-cf-protection.c b/test/CodeGen/x86-cf-protection.c new file mode 100644 index 0000000000..bc64bfa64f --- /dev/null +++ b/test/CodeGen/x86-cf-protection.c @@ -0,0 +1,6 @@ +// RUN: not %clang_cc1 -fsyntax-only -S -emit-llvm -triple i386-unknown-unknown -fcf-protection=return %s 2>&1 | FileCheck %s --check-prefix=RETURN +// RUN: not %clang_cc1 -fsyntax-only -S -emit-llvm -triple i386-unknown-unknown -fcf-protection=branch %s 2>&1 | FileCheck %s --check-prefix=BRANCH + +// RETURN: error: option 'cf-protection=return' cannot be specified without '-mshstk' +// BRANCH: error: option 'cf-protection=branch' cannot be specified without '-mibt' +void foo() {} diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c index b22f74fb55..5755c5d36f 100644 --- a/test/Driver/clang_f_opts.c +++ b/test/Driver/clang_f_opts.c @@ -503,3 +503,17 @@ // CHECK-WINDOWS-ISO10646: "-fwchar-type=int" // CHECK-WINDOWS-ISO10646: "-fsigned-wchar" +// RUN: %clang -### -S -fcf-protection %s 2>&1 | FileCheck -check-prefix=CHECK-CF-PROTECTION-FULL %s +// RUN: %clang -### -S %s 2>&1 | FileCheck -check-prefix=CHECK-NO-CF-PROTECTION-FULL %s +// RUN: %clang -### -S -fcf-protection=full %s 2>&1 | FileCheck -check-prefix=CHECK-CF-PROTECTION-FULL %s +// RUN: %clang -### -S %s 2>&1 | FileCheck -check-prefix=CHECK-NO-CF-PROTECTION-FULL %s +// CHECK-CF-PROTECTION-FULL: -fcf-protection=full +// CHECK-NO-CF-PROTECTION-FULL-NOT: -fcf-protection=full +// RUN: %clang -### -S -fcf-protection=return %s 2>&1 | FileCheck -check-prefix=CHECK-CF-PROTECTION-RETURN %s +// RUN: %clang -### -S %s 2>&1 | FileCheck -check-prefix=CHECK-NO-CF-PROTECTION-RETURN %s +// CHECK-CF-PROTECTION-RETURN: -fcf-protection=return +// CHECK-NO-CF-PROTECTION-RETURN-NOT: -fcf-protection=return +// RUN: %clang -### -S -fcf-protection=branch %s 2>&1 | FileCheck -check-prefix=CHECK-CF-PROTECTION-BRANCH %s +// RUN: %clang -### -S %s 2>&1 | FileCheck -check-prefix=CHECK-NO-CF-PROTECTION-BRANCH %s +// CHECK-CF-PROTECTION-BRANCH: -fcf-protection=branch +// CHECK-NO-CF-PROTECTION-BRANCH-NOT: -fcf-protection=branch