-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[X86][KCFI] Do not emit a type prefix for nocf_check functions #158133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
With indirect branch protection, the `nocf_check` attribute prevents a function from being called indirectly by omitting the ENDBR instruction from the beginning of the function body. As KCFI type prefixes are only needed for indirectly callable functions, don't emit the unnecessary prefix for `nocf_check` functions.
@llvm/pr-subscribers-clang @llvm/pr-subscribers-backend-x86 Author: Sami Tolvanen (samitolvanen) ChangesWith indirect branch protection, the Full diff: https://github.com/llvm/llvm-project/pull/158133.diff 2 Files Affected:
diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp
index ff22ee8c86fac..486bf3986cf5a 100644
--- a/llvm/lib/Target/X86/X86AsmPrinter.cpp
+++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp
@@ -170,8 +170,9 @@ void X86AsmPrinter::emitKCFITypeId(const MachineFunction &MF) {
Type = mdconst::extract<ConstantInt>(MD->getOperand(0));
// If we don't have a type to emit, just emit padding if needed to maintain
- // the same alignment for all functions.
- if (!Type) {
+ // the same alignment for all functions. Also skip `nocf_check` functions as
+ // they are not indirectly callable due to a missing ENDBR.
+ if (!Type || F.doesNoCfCheck()) {
EmitKCFITypePadding(MF, /*HasType=*/false);
return;
}
diff --git a/llvm/test/CodeGen/X86/kcfi-nocf-check.ll b/llvm/test/CodeGen/X86/kcfi-nocf-check.ll
new file mode 100644
index 0000000000000..1ce886c1587f8
--- /dev/null
+++ b/llvm/test/CodeGen/X86/kcfi-nocf-check.ll
@@ -0,0 +1,39 @@
+; RUN: llc -mtriple=x86_64-unknown-unknown -x86-indirect-branch-tracking < %s | FileCheck %s
+
+; CHECK-LABEL: __cfi_cf_check_func:
+; CHECK: movl $12345678, %eax
+define void @cf_check_func() !kcfi_type !2 {
+; CHECK-LABEL: cf_check_func:
+; CHECK: endbr64
+; CHECK: retq
+entry:
+ ret void
+}
+
+; CHECK-NOT: __cfi_notype_cf_check_func:
+; CHECK-NOT: movl
+define void @notype_cf_check_func() {
+; CHECK-LABEL: notype_cf_check_func:
+; CHECK: endbr64
+; CHECK: retq
+entry:
+ ret void
+}
+
+; CHECK-NOT: __cfi_nocf_check_func:
+; CHECK-NOT: movl
+define void @nocf_check_func() #0 !kcfi_type !2 {
+; CHECK-LABEL: nocf_check_func:
+; CHECK-NOT: endbr64
+; CHECK: retq
+entry:
+ ret void
+}
+
+attributes #0 = { nocf_check }
+
+!llvm.module.flags = !{!0, !1}
+
+!0 = !{i32 8, !"cf-protection-branch", i32 1}
+!1 = !{i32 4, !"kcfi", i32 1}
+!2 = !{i32 12345678}
|
ret void | ||
} | ||
|
||
; CHECK-NOT: __cfi_notype_cf_check_func: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We just need one CHECK-NOT: __cfi_
and the next ; CHECK-NOT: __cfi_nocf_check_func:
can be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We just need one
CHECK-NOT: __cfi_
and the next; CHECK-NOT: __cfi_nocf_check_func:
can be removed.
Do you mean something like this?
; CHECK-NOT: __cfi_
define void @notype_cf_check_func() {
; CHECK-LABEL: notype_cf_check_func:
; CHECK: endbr64
; CHECK: retq
entry:
ret void
}
define void @nocf_check_func() #0 !kcfi_type !2 {
; CHECK-LABEL: nocf_check_func:
; CHECK-NOT: endbr64
; CHECK: retq
entry:
ret void
}
Perhaps I misunderstood your comment, because if we now end up emitting a __cfi_
type prefix before nocf_check_func
, FileCheck is not going to detect that. We're still going to need a second CHECK-NOT: __cfi_
before nocf_check_func
to catch this case.
Am I missing some clever FileCheck trick that would make this simpler?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see this is only testing the IR level, but not the front-end. Do you want -fsanitize=kcfi
to work with nocf_check
regardless of -fcf-protection
? I think it should -- there may actually be some value in being able to remove preambles for a function regardless of -fcf-protection
. (This is the logic I'm implementing in the GCC KCFI.)
That way we won't get these kinds of errors if someone tries to use nocf_check
:
kcfi-runtime.c:17:16: warning: 'nocf_check' attribute ignored; use -fcf-protection to enable the
attribute [-Wignored-attributes]
17 | __attribute__((nocf_check))
| ^
Correct, this doesn't change the behavior of
That sounds reasonable to me. Out of curiosity,
I think this isn't actually a problem in the kernel though, as |
I modified the
Correct. In the future we could modify the |
Looking at this a bit closer, the Edit: RISC-V also supports |
Wait, like, as variable/struct-member attribute?
Yeah, I was only looking at disabling the KCFI preamble generation. I was following Clang's KCFI implementation so
Hm, this is getting a bit weird. Perhaps we should instead leave |
For function pointer types, specifically. Performing an indirect call through a
Adding a new attribute would certainly avoid the corner cases with |
With indirect branch protection, the
nocf_check
attribute prevents a function from being called indirectly by omitting the ENDBR instruction from the beginning of the function body. As KCFI type prefixes are only needed for indirectly callable functions, don't emit the unnecessary prefix fornocf_check
functions.