oren_ben_simhon created this revision. oren_ben_simhon added reviewers: erichkeane, craig.topper, AndreiGrischenko, aaboud. Herald added subscribers: llvm-commits, javed.absar.
The patch adds nocf_check target independent attribute for disabling checks that were enabled by cf-protection flag. The attribute can be appertained to functions and function pointers. Attribute name follows GCC's similar attribute name. Please see the following for more information: https://reviews.llvm.org/D41879 Repository: rL LLVM https://reviews.llvm.org/D41880 Files: include/clang/AST/Type.h include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Sema/Sema.h lib/AST/Type.cpp lib/AST/TypePrinter.cpp lib/CodeGen/CGCall.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaType.cpp test/CodeGen/attributes.c test/CodeGen/cetintrin.c test/CodeGen/x86-cf-protection.c test/Sema/attr-nocf_check.c
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 __attribute__((nocf_check)) testNoCfCheck(){}; // no-warning + +// No variable or parameter declaration +__attribute__((nocf_check)) int i; // expected-warning {{'nocf_check' attribute only applies to functions and methods}} +void testNoCfCheckImpl(double __attribute__((nocf_check)) i) {} // expected-warning {{'nocf_check' attribute only applies to functions and methods}} + +// 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}} 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 -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 +// RUN: not %clang_cc1 -fsyntax-only -S -triple i386-unknown-unknown -fcf-protection=return %s 2>&1 | FileCheck %s --check-prefix=RETURN +// RUN: not %clang_cc1 -fsyntax-only -S -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/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 <immintrin.h> 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: 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: 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<ObjCMethodDecl>(D)) { @@ -1980,35 +1980,47 @@ 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) || S.CheckAttrNoArgs(attr)) + return; + + if (!isFunctionOrMethod(D)) { + ValueDecl *VD = dyn_cast<ValueDecl>(D); + if (!VD || (!VD->getType()->isFunctionPointerType())) { + S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << attr.getName() << ExpectedFunctionOrMethod; + 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(); Attr.setInvalid(); return true; } - if (!checkAttributeNumArgs(*this, Attr, 0)) { - Attr.setInvalid(); - return true; - } - return false; } @@ -6197,6 +6209,9 @@ case AttributeList::AT_NoReturn: handleNoReturnAttr(S, D, Attr); break; + case AttributeList::AT_AnyX86NoCfCheck: + handleNoCfCheckAttr(S, D, Attr); + break; case AttributeList::AT_NoThrow: handleSimpleAttribute<NoThrowAttr>(S, D, Attr); 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<AnyX86NoCallerSavedRegistersAttr>()) FuncAttrs.addAttribute("no_caller_saved_registers"); + if (TargetDecl->hasAttr<AnyX86NoCfCheckAttr>()) + FuncAttrs.addAttribute(llvm::Attribute::NoCfCheck); HasOptnone = TargetDecl->hasAttr<OptimizeNoneAttr>(); if (auto *AllocSize = TargetDecl->getAttr<AllocSizeAttr>()) { Index: lib/AST/TypePrinter.cpp =================================================================== --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -1395,8 +1395,8 @@ // 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_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/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: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -3325,8 +3325,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: 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 addresses used by +indirect call / jmp, e.g. redirect control-flow to non-programmer +intended bytes in 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/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -2085,6 +2085,11 @@ let Documentation = [AnyX86NoCallerSavedRegistersDocs]; } +def AnyX86NoCfCheck : InheritableAttr, TargetSpecificAttr<TargetAnyX86>{ + let Spellings = [GCC<"nocf_check">]; + let Documentation = [AnyX86NoCfCheckDocs]; +} + def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetAnyX86> { let Spellings = [GCC<"force_align_arg_pointer">]; // Technically, this appertains to a FunctionDecl, but the target-specific 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,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits