[clang][slh] add attribute for speculative load hardening

Summary:
LLVM IR already has an attribute for speculative_load_hardening. Before
this commit, when a user passed the -mspeculative-load-hardening flag to
Clang, every function would have this attribute added to it. This Clang
attribute will allow users to opt into SLH on a function by function basis.

This can be applied to functions and Objective C methods.

Reviewers: chandlerc, echristo

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D54555

llvm-svn: 347586
This commit is contained in:
Zola Bridges 2018-11-26 19:41:14 +00:00
parent 94104b1b6b
commit b0fd2db8fc
8 changed files with 107 additions and 13 deletions

View File

@ -3091,3 +3091,9 @@ def AlwaysDestroy : InheritableAttr {
let Subjects = SubjectList<[Var]>;
let Documentation = [AlwaysDestroyDocs];
}
def SpeculativeLoadHardening : InheritableAttr {
let Spellings = [Clang<"speculative_load_hardening">];
let Subjects = SubjectList<[Function, ObjCMethod], ErrorDiag>;
let Documentation = [SpeculativeLoadHardeningDocs];
}

View File

@ -3629,3 +3629,27 @@ GNU inline semantics are the default behavior with ``-std=gnu89``,
``-std=c89``, ``-std=c94``, or ``-fgnu89-inline``.
}];
}
def SpeculativeLoadHardeningDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
This attribute can be applied to a function declaration in order to indicate
that `Speculative Load Hardening <https://llvm.org/docs/SpeculativeLoadHardening.html>`_
should be enabled for the function body. This can also be applied to a method
in Objective C.
Speculative Load Hardening is a best-effort mitigation against
information leak attacks that make use of control flow
miss-speculation - specifically miss-speculation of whether a branch
is taken or not. Typically vulnerabilities enabling such attacks are
classified as "Spectre variant #1". Notably, this does not attempt to
mitigate against miss-speculation of branch target, classified as
"Spectre variant #2" vulnerabilities.
When inlining, the attribute is sticky. Inlining a function that
carries this attribute will cause the caller to gain the
attribute. This is intended to provide a maximally conservative model
where the code in a function annotated with this attribute will always
(even after inlining) end up hardened.
}];
}

View File

@ -1791,6 +1791,8 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
if (CodeGenOpts.Backchain)
FuncAttrs.addAttribute("backchain");
// FIXME: The interaction of this attribute with the SLH command line flag
// has not been determined.
if (CodeGenOpts.SpeculativeLoadHardening)
FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening);
}
@ -1854,6 +1856,8 @@ void CodeGenModule::ConstructAttributeList(
FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate);
if (TargetDecl->hasAttr<ConvergentAttr>())
FuncAttrs.addAttribute(llvm::Attribute::Convergent);
if (TargetDecl->hasAttr<SpeculativeLoadHardeningAttr>())
FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening);
if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
AddAttributesFromFunctionProtoType(

View File

@ -6373,6 +6373,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_Section:
handleSectionAttr(S, D, AL);
break;
case ParsedAttr::AT_SpeculativeLoadHardening:
handleSimpleAttribute<SpeculativeLoadHardeningAttr>(S, D, AL);
break;
case ParsedAttr::AT_CodeSeg:
handleCodeSegAttr(S, D, AL);
break;

View File

@ -0,0 +1,18 @@
// RUN: %clang_cc1 -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK1
// RUN: %clang_cc1 -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK2
//
// Check that we set the attribute on each function.
[[clang::speculative_load_hardening]]
int test1() {
return 42;
}
int __attribute__((speculative_load_hardening)) test2() {
return 42;
}
// CHECK1: @{{.*}}test1{{.*}}[[SLH1:#[0-9]+]]
// CHECK1: attributes [[SLH1]] = { {{.*}}speculative_load_hardening{{.*}} }
// CHECK2: @{{.*}}test2{{.*}}[[SLH2:#[0-9]+]]
// CHECK2: attributes [[SLH2]] = { {{.*}}speculative_load_hardening{{.*}} }

View File

@ -0,0 +1,9 @@
// RUN: %clang -emit-llvm %s -o - -S | FileCheck %s -check-prefix=SLH
int main() __attribute__((speculative_load_hardening)) {
return 0;
}
// SLH: @{{.*}}main{{.*}}[[SLH:#[0-9]+]]
// SLH: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} }

View File

@ -0,0 +1,34 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
int i __attribute__((speculative_load_hardening)); // expected-error {{'speculative_load_hardening' attribute only applies to functions}}
void f1() __attribute__((speculative_load_hardening));
void f2() __attribute__((speculative_load_hardening(1))); // expected-error {{'speculative_load_hardening' attribute takes no arguments}}
template <typename T>
void tf1() __attribute__((speculative_load_hardening));
int f3(int __attribute__((speculative_load_hardening)), int); // expected-error {{'speculative_load_hardening' attribute only applies to functions}}
struct A {
int f __attribute__((speculative_load_hardening)); // expected-error {{'speculative_load_hardening' attribute only applies to functions}}
void mf1() __attribute__((speculative_load_hardening));
static void mf2() __attribute__((speculative_load_hardening));
};
int ci [[speculative_load_hardening]]; // expected-error {{'speculative_load_hardening' attribute only applies to functions}}
[[speculative_load_hardening]] void cf1();
[[speculative_load_hardening(1)]] void cf2(); // expected-error {{'speculative_load_hardening' attribute takes no arguments}}
template <typename T>
[[speculative_load_hardening]]
void ctf1();
int cf3(int c[[speculative_load_hardening]], int); // expected-error {{'speculative_load_hardening' attribute only applies to functions}}
struct CA {
int f [[speculative_load_hardening]]; // expected-error {{'speculative_load_hardening' attribute only applies to functions}}
[[speculative_load_hardening]] void mf1();
[[speculative_load_hardening]] static void mf2();
};

View File

@ -1643,19 +1643,15 @@ example:
``speculative_load_hardening``
This attribute indicates that
`Speculative Load Hardening <https://llvm.org/docs/SpeculativeLoadHardening.html>`_
should be enabled for the function body. This is a best-effort attempt to
mitigate all known speculative execution information leak vulnerabilities
that are based on the fundamental principles of modern processors'
speculative execution. These vulnerabilities are classified as "Spectre
variant #1" vulnerabilities typically. Notably, this does not attempt to
mitigate any vulnerabilities where the speculative execution and/or
prediction devices of specific processors can be *completely* undermined
(such as "Branch Target Injection", a.k.a, "Spectre variant #2"). Instead,
this is a target-independent request to harden against the completely
generic risk posed by speculative execution to incorrectly load secret data,
making it available to some micro-architectural side-channel for information
leak. For a processor without any speculative execution or predictors, this
is expected to be a no-op.
should be enabled for the function body.
Speculative Load Hardening is a best-effort mitigation against
information leak attacks that make use of control flow
miss-speculation - specifically miss-speculation of whether a branch
is taken or not. Typically vulnerabilities enabling such attacks are
classified as "Spectre variant #1". Notably, this does not attempt to
mitigate against miss-speculation of branch target, classified as
"Spectre variant #2" vulnerabilities.
When inlining, the attribute is sticky. Inlining a function that carries
this attribute will cause the caller to gain the attribute. This is intended