Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -4054,6 +4054,7 @@ // No operand. attr_noreturn, + attr_nocf_check, attr_cdecl, attr_fastcall, attr_stdcall, Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -2085,6 +2085,12 @@ let Documentation = [AnyX86NoCallerSavedRegistersDocs]; } +def AnyX86NoCfCheck : InheritableAttr, TargetSpecificAttr{ + let Spellings = [GCC<"nocf_check">]; + let Subjects = SubjectList<[FunctionLike]>; + let Documentation = [AnyX86NoCfCheckDocs]; +} + def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr { let Spellings = [GCC<"force_align_arg_pointer">]; // Technically, this appertains to a FunctionDecl, but the target-specific Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -2870,6 +2870,24 @@ }]; } +def AnyX86NoCfCheckDocs : Documentation{ + let Category = DocCatFunction; + let Content = [{ +Jump Oriented Programming attacks rely on tampering with addresses used by +indirect call / jmp, e.g. redirect control-flow to non-programmer +intended bytes in the binary. +X86 Supports Indirect Branch Tracking (IBT) as part of Control-Flow +Enforcement Technology (CET). IBT instruments ENDBR instructions used to +specify valid targets of indirect call / jmp. +The ``nocf_check`` attribute has two roles: +1. Appertains to a function - do not add ENDBR instruction at the + beginning of the function. +2. Appertains to a function pointer - do not track the target + function of this pointer (by adding nocf_check prefix to the + indirect-call instruction). +}]; +} + def SwiftCallDocs : Documentation { let Category = DocCatVariable; let Content = [{ Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -3328,8 +3328,8 @@ bool CheckRegparmAttr(const AttributeList &attr, unsigned &value); bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, const FunctionDecl *FD = nullptr); - bool CheckNoReturnAttr(const AttributeList &attr); - bool CheckNoCallerSavedRegsAttr(const AttributeList &attr); + bool CheckAttrTarget(const AttributeList &Attr); + bool CheckAttrNoArgs(const AttributeList &Attr); bool checkStringLiteralArgumentAttr(const AttributeList &Attr, unsigned ArgNum, StringRef &Str, SourceLocation *ArgLocation = nullptr); Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -3097,6 +3097,7 @@ case AttributedType::attr_uptr: case AttributedType::attr_objc_kindof: case AttributedType::attr_ns_returns_retained: + case AttributedType::attr_nocf_check: return false; } llvm_unreachable("bad attributed type kind"); @@ -3134,6 +3135,7 @@ case attr_nullable: case attr_null_unspecified: case attr_objc_kindof: + case attr_nocf_check: return false; case attr_pcs: Index: lib/AST/TypePrinter.cpp =================================================================== --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -1396,7 +1396,7 @@ // FIXME: When Sema learns to form this AttributedType, avoid printing the // attribute again in printFunctionProtoAfter. case AttributedType::attr_noreturn: OS << "noreturn"; break; - + case AttributedType::attr_nocf_check: OS << "nocf_check"; break; case AttributedType::attr_cdecl: OS << "cdecl"; break; case AttributedType::attr_fastcall: OS << "fastcall"; break; case AttributedType::attr_stdcall: OS << "stdcall"; break; Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -1842,6 +1842,8 @@ RetAttrs.addAttribute(llvm::Attribute::NonNull); if (TargetDecl->hasAttr()) FuncAttrs.addAttribute("no_caller_saved_registers"); + if (TargetDecl->hasAttr()) + FuncAttrs.addAttribute(llvm::Attribute::NoCfCheck); HasOptnone = TargetDecl->hasAttr(); if (auto *AllocSize = TargetDecl->getAttr()) { Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -1965,7 +1965,7 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &Attrs) { if (hasDeclarator(D)) return; - if (S.CheckNoReturnAttr(Attrs)) + if (S.CheckAttrNoArgs(Attrs)) return; if (!isa(D)) { @@ -1980,23 +1980,31 @@ static void handleNoCallerSavedRegsAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (S.CheckNoCallerSavedRegsAttr(Attr)) + if (S.CheckAttrTarget(Attr) || S.CheckAttrNoArgs(Attr)) return; D->addAttr(::new (S.Context) AnyX86NoCallerSavedRegistersAttr( Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); } -bool Sema::CheckNoReturnAttr(const AttributeList &Attrs) { - if (!checkAttributeNumArgs(*this, Attrs, 0)) { - Attrs.setInvalid(); +static void handleNoCfCheckAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (S.CheckAttrTarget(Attr)) + return; + + D->addAttr(::new (S.Context) AnyX86NoCfCheckAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); +} + +bool Sema::CheckAttrNoArgs(const AttributeList &Attr) { + if (!checkAttributeNumArgs(*this, Attr, 0)) { + Attr.setInvalid(); return true; } return false; } -bool Sema::CheckNoCallerSavedRegsAttr(const AttributeList &Attr) { +bool Sema::CheckAttrTarget(const AttributeList &Attr) { // Check whether the attribute is valid on the current target. if (!Attr.existsInTarget(Context.getTargetInfo())) { Diag(Attr.getLoc(), diag::warn_unknown_attribute_ignored) << Attr.getName(); @@ -2004,11 +2012,6 @@ return true; } - if (!checkAttributeNumArgs(*this, Attr, 0)) { - Attr.setInvalid(); - return true; - } - return false; } @@ -6197,6 +6200,9 @@ case AttributeList::AT_NoReturn: handleNoReturnAttr(S, D, Attr); break; + case AttributeList::AT_AnyX86NoCfCheck: + handleNoCfCheckAttr(S, D, Attr); + break; case AttributeList::AT_NoThrow: handleSimpleAttribute(S, D, Attr); break; Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -5127,6 +5127,8 @@ return AttributeList::AT_ObjCOwnership; case AttributedType::attr_noreturn: return AttributeList::AT_NoReturn; + case AttributedType::attr_nocf_check: + return AttributeList::AT_AnyX86NoCfCheck; case AttributedType::attr_cdecl: return AttributeList::AT_CDecl; case AttributedType::attr_fastcall: @@ -6592,7 +6594,7 @@ FunctionTypeUnwrapper unwrapped(S, type); if (attr.getKind() == AttributeList::AT_NoReturn) { - if (S.CheckNoReturnAttr(attr)) + if (S.CheckAttrNoArgs(attr)) return true; // Delay if this is not a function type. @@ -6632,7 +6634,7 @@ } if (attr.getKind() == AttributeList::AT_AnyX86NoCallerSavedRegisters) { - if (S.CheckNoCallerSavedRegsAttr(attr)) + if (S.CheckAttrTarget(attr) || S.CheckAttrNoArgs(attr)) return true; // Delay if this is not a function type. Index: test/CodeGen/attributes.c =================================================================== --- test/CodeGen/attributes.c +++ test/CodeGen/attributes.c @@ -97,8 +97,20 @@ // CHECK: define void @t22() [[NUW]] section ".bar" +// CHECK: define void @t23() [[NOCF_CHECK_FUNC:#[0-9]+]] +void __attribute__((nocf_check)) t23(void) {} + +// CHECK: call void %{{[a-z0-9]+}}() [[NOCF_CHECK_CALL:#[0-9]+]] +typedef void (*f_t)(void); +void t24(f_t f1) { + __attribute__((nocf_check)) f_t p = f1; + (*p)(); +} + // CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} } // CHECK: attributes [[NR]] = { noinline noreturn nounwind{{.*}} } // CHECK: attributes [[COLDDEF]] = { cold {{.*}}} // CHECK: attributes [[COLDDECL]] = { cold {{.*}}} +// CHECK: attributes [[NOCF_CHECK_FUNC]] = { nocf_check {{.*}}} // CHECK: attributes [[COLDSITE]] = { cold {{.*}}} +// CHECK: attributes [[NOCF_CHECK_CALL]] = { nocf_check } Index: test/CodeGen/cetintrin.c =================================================================== --- test/CodeGen/cetintrin.c +++ test/CodeGen/cetintrin.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -ffreestanding %s -triple=i386-apple-darwin -target-feature +shstk -emit-llvm -o - -Wall -Werror | FileCheck %s -// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +shstk -emit-llvm -o - -Wall -Werror | FileCheck %s --check-prefix=X86_64 +// RUN: %clang_cc1 -ffreestanding %s -triple=i386-unknown-unknown -target-feature +shstk -emit-llvm -o - -Wall -Werror | FileCheck %s +// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-unknown-unknown -target-feature +shstk -emit-llvm -o - -Wall -Werror | FileCheck %s --check-prefix=X86_64 #include Index: test/CodeGen/x86-cf-protection.c =================================================================== --- test/CodeGen/x86-cf-protection.c +++ test/CodeGen/x86-cf-protection.c @@ -1,5 +1,5 @@ -// RUN: not %clang_cc1 -fsyntax-only -S -emit-llvm -o %t -triple i386-unknown-unknown -fcf-protection=return %s 2>&1 | FileCheck %s --check-prefix=RETURN -// RUN: not %clang_cc1 -fsyntax-only -S -emit-llvm -o %t -triple i386-unknown-unknown -fcf-protection=branch %s 2>&1 | FileCheck %s --check-prefix=BRANCH +// RUN: not %clang_cc1 -fsyntax-only -S -o %t -triple i386-unknown-unknown -fcf-protection=return %s 2>&1 | FileCheck %s --check-prefix=RETURN +// RUN: not %clang_cc1 -fsyntax-only -S -o %t -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' Index: test/Misc/pragma-attribute-supported-attributes-list.test =================================================================== --- test/Misc/pragma-attribute-supported-attributes-list.test +++ test/Misc/pragma-attribute-supported-attributes-list.test @@ -2,7 +2,7 @@ // The number of supported attributes should never go down! -// CHECK: #pragma clang attribute supports 66 attributes: +// CHECK: #pragma clang attribute supports 67 attributes: // CHECK-NEXT: AMDGPUFlatWorkGroupSize (SubjectMatchRule_function) // CHECK-NEXT: AMDGPUNumSGPR (SubjectMatchRule_function) // CHECK-NEXT: AMDGPUNumVGPR (SubjectMatchRule_function) @@ -12,6 +12,7 @@ // CHECK-NEXT: AlignValue (SubjectMatchRule_variable, SubjectMatchRule_type_alias) // CHECK-NEXT: AllocSize (SubjectMatchRule_function) // CHECK-NEXT: Annotate () +// CHECK-NEXT: AnyX86NoCfCheck (SubjectMatchRule_hasType_functionType) // CHECK-NEXT: AssumeAligned (SubjectMatchRule_objc_method, SubjectMatchRule_function) // CHECK-NEXT: Availability ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable)) // CHECK-NEXT: CXX11NoReturn (SubjectMatchRule_function) Index: test/Sema/attr-nocf_check.c =================================================================== --- /dev/null +++ test/Sema/attr-nocf_check.c @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -verify -fsyntax-only %s + +// Function pointer definition. +typedef void (*FuncPointerWithNoCfCheck)(void) __attribute__((nocf_check)); // no-warning +typedef void (*FuncPointer)(void); + +// Allow function declaration and definition mismatch. +void __attribute__((nocf_check)) testNoCfCheck(); // no-warning +void testNoCfCheck(){}; // no-warning + +// No variable or parameter declaration +__attribute__((nocf_check)) int i; // expected-warning {{'nocf_check' attribute only applies to functions and function pointers}} +void testNoCfCheckImpl(double __attribute__((nocf_check)) i) {} // expected-warning {{'nocf_check' attribute only applies to functions and function pointers}} + +// Allow attributed function pointers as well as casting between attributed +// and non-attributed function pointers. +void testNoCfCheckMismatch(FuncPointer f) { + FuncPointerWithNoCfCheck fNoCfCheck = f; // no-warning + (*fNoCfCheck)(); // no-warning + f = fNoCfCheck; // no-warning +} + +// 'nocf_check' Attribute has no parameters. +int testNoCfCheckParams() __attribute__((nocf_check(1))); // expected-error {{'nocf_check' attribute takes no arguments}}