Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -3091,3 +3091,15 @@ let Subjects = SubjectList<[Var]>; let Documentation = [AlwaysDestroyDocs]; } + +def SpeculativeLoadHardening : InheritableAttr { + let Spellings = [Clang<"speculative_load_hardening">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [SpeculativeLoadHardeningDocs]; +} + +def NoSpeculativeLoadHardening : InheritableAttr { + let Spellings = [Clang<"no_speculative_load_hardening">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [NoSpeculativeLoadHardeningDocs]; +} Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -3629,3 +3629,43 @@ ``-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 `_ + 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 to provide a maximally conservative model + where the code in a function annotated with this attribute will always + (even after inlining) end up hardened. + }]; +} + +def NoSpeculativeLoadHardeningDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ + This attribute can be applied to a function declaration in order to indicate + that `Speculative Load Hardening `_ + should NOT be enabled for the function body. + + Warning: This attribute may not prevent Speculative Load Hardening from being + enabled for a function which inlines a function that has the + 'speculative_load_hardening' attribute. This is intended to provide a + maximally conservative model where the code that is marked with the + 'speculative_load_hardening' attribute will always (even as inlining) + be hardened. A user of this attribute may want to mark functions called by + a function they do not want to be hardened with the 'noinline' attribute. + }]; +} Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -1898,6 +1898,16 @@ ConstructDefaultFnAttrList(Name, HasOptnone, AttrOnCallSite, FuncAttrs); + // This must run after constructing the default function attribute list + // to ensure that the speculative load hardening attribute is removed + // in the case where the -mspeculative-load-hardening flag was passed. + if (TargetDecl) { + if (TargetDecl->hasAttr()) + FuncAttrs.removeAttribute(llvm::Attribute::SpeculativeLoadHardening); + if (TargetDecl->hasAttr()) + FuncAttrs.addAttribute(llvm::Attribute::SpeculativeLoadHardening); + } + if (CodeGenOpts.EnableSegmentedStacks && !(TargetDecl && TargetDecl->hasAttr())) FuncAttrs.addAttribute("split-stack"); Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -6373,6 +6373,12 @@ case ParsedAttr::AT_Section: handleSectionAttr(S, D, AL); break; + case ParsedAttr::AT_SpeculativeLoadHardening: + handleSimpleAttribute(S, D, AL); + break; + case ParsedAttr::AT_NoSpeculativeLoadHardening: + handleSimpleAttribute(S, D, AL); + break; case ParsedAttr::AT_CodeSeg: handleCodeSegAttr(S, D, AL); break; Index: clang/test/CodeGen/attr-speculative-load-hardening.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/attr-speculative-load-hardening.cpp @@ -0,0 +1,61 @@ +// Check that we set the attribute on each function. +// 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 did not set the attribute on each function +// RUN: %clang_cc1 -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK7 +// RUN: %clang_cc1 -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK8 + + +// Check that we did not set the attribute on each function despite the +// -mspeculative-load-hardening flag. +// RUN: %clang_cc1 -mspeculative-load-hardening -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK3 +// RUN: %clang_cc1 -mspeculative-load-hardening -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK4 + + +// Check that we did set the attribute on each function despite the +// -mno-speculative-load-hardening flag. +// RUN: %clang -mno-speculative-load-hardening -S -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK5 +// RUN: %clang -mno-speculative-load-hardening -S -std=c++11 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK6 + + +[[clang::speculative_load_hardening]] +int test1() { + return 42; +} + +int __attribute__((speculative_load_hardening)) test2() { + return 42; +} + +[[clang::no_speculative_load_hardening]] +int test3() { + return 42; +} + +int __attribute__((no_speculative_load_hardening)) test4() { + return 42; +} +// CHECK1: @{{.*}}test1{{.*}}[[SLH:#[0-9]+]] +// CHECK1: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} } + +// CHECK2: @{{.*}}test2{{.*}}[[SLH:#[0-9]+]] +// CHECK2: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} } +// +// CHECK7: @{{.*}}test3{{.*}}[[SLH:#[0-9]+]] +// CHECK7-NOT: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} } + +// CHECK8: @{{.*}}test4{{.*}}[[SLH:#[0-9]+]] +// CHECK8-NOT: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} } + +// CHECK3: @{{.*}}test3{{.*}}[[SLH:#[0-9]+]] +// CHECK3-NOT: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} } + +// CHECK4: @{{.*}}test4{{.*}}[[SLH:#[0-9]+]] +// CHECK4-NOT: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} } + +// CHECK5: @{{.*}}test1{{.*}}[[SLH:#[0-9]+]] +// CHECK5: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} } + +// CHECK6: @{{.*}}test2{{.*}}[[SLH:#[0-9]+]] +// CHECK6: attributes [[SLH]] = { {{.*}}speculative_load_hardening{{.*}} } Index: clang/test/SemaCXX/attr-speculative-load-hardening.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/attr-speculative-load-hardening.cpp @@ -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 +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 +[[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(); +};