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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits