-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[AArch64][FMV] Enable PAuth and BTI hardening of resolver functions #141573
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
93eca6d
to
c5a7fea
Compare
@llvm/pr-subscribers-clang-codegen @llvm/pr-subscribers-clang Author: Anatoly Trosinenko (atrosinenko) ChangesFull diff: https://github.com/llvm/llvm-project/pull/141573.diff 2 Files Affected:
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 16e010adbeb5f..af8d4cc60de57 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4638,6 +4638,13 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
if (FD->isTargetMultiVersion() || FD->isTargetClonesMultiVersion())
AddDeferredMultiVersionResolverToEmit(GD);
+ auto SetResolverAttrs = [&](llvm::Function &Resolver) {
+ TargetInfo::BranchProtectionInfo BPI(getLangOpts());
+ TargetCodeGenInfo::setBranchProtectionFnAttributes(BPI, Resolver);
+ TargetCodeGenInfo::setPointerAuthFnAttributes(CodeGenOpts.PointerAuth,
+ Resolver);
+ };
+
// For cpu_specific, don't create an ifunc yet because we don't know if the
// cpu_dispatch will be emitted in this translation unit.
if (ShouldReturnIFunc) {
@@ -4652,6 +4659,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
"", Resolver, &getModule());
GIF->setName(ResolverName);
SetCommonAttributes(FD, GIF);
+ SetResolverAttrs(cast<llvm::Function>(*Resolver));
if (ResolverGV)
replaceDeclarationWith(ResolverGV, GIF);
return GIF;
@@ -4662,6 +4670,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
assert(isa<llvm::GlobalValue>(Resolver) && !ResolverGV &&
"Resolver should be created for the first time");
SetCommonAttributes(FD, cast<llvm::GlobalValue>(Resolver));
+ SetResolverAttrs(cast<llvm::Function>(*Resolver));
return Resolver;
}
diff --git a/clang/test/CodeGen/ptrauth-resolver-attributes.c b/clang/test/CodeGen/ptrauth-resolver-attributes.c
new file mode 100644
index 0000000000000..8bdedd2c549be
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-resolver-attributes.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,BTI-SIGNRA %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,BTI-SIGNRA %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s
+
+// Check that resolver functions generated by clang have the correct attributes.
+
+int __attribute__((target_clones("crc", "default"))) ftc(void) { return 0; }
+
+int __attribute__((target_version("crc"))) fmv(void) { return 0; }
+int __attribute__((target_version("default"))) fmv(void) { return 0; }
+
+// CHECK: define{{.*}} i32 @ftc._Mcrc() #0
+// CHECK: define{{.*}} ptr @ftc.resolver() #1
+// CHECK: define{{.*}} i32 @fmv._Mcrc() #0
+// CHECK: define{{.*}} i32 @fmv.default() #2
+// CHECK: define{{.*}} i32 @ftc.default() #2
+// CHECK: define{{.*}} ptr @fmv.resolver() #1
+
+// BTI-SIGNRA: attributes #0 = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
+// BTI-SIGNRA: attributes #1 = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
+// BTI-SIGNRA: attributes #2 = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
+// PAUTHTEST: attributes #0 = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
+// PAUTHTEST: attributes #1 = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
+// PAUTHTEST: attributes #2 = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
|
clang/lib/CodeGen/CodeGenModule.cpp
Outdated
@@ -4652,6 +4659,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { | |||
"", Resolver, &getModule()); | |||
GIF->setName(ResolverName); | |||
SetCommonAttributes(FD, GIF); | |||
SetResolverAttrs(cast<llvm::Function>(Resolver)); |
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.
Is Resolver actually guaranteed to be a function? GetOrCreateLLVMFunction can return other kinds of GlobalValues in some cases.
Should we be calling SetCommonAttributes/setGVProperties to set the linkage/visibility of the resolver?
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.
GlobalIFunc
instructions in the IR currently require that the resolver be a Function
with a definition.
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 think the question "Should we be calling SetCommonAttributes/setGVProperties to set the linkage/visibility of the resolver?" was never answered.
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.
@efriedma-quic, are you suggesting to remove the call to SetCommonAttributes
just above? That would make the resolver non dso_local
, which isn't desirable I think. There are tests in place that will start failing.
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.
The part I'm concerned about is that ftc.resolver
in the testcase is missing attributes: it's not dso_local, it doesn't get marked "hidden" if you pass -fvisibility=hidden, etc.
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.
However at this point, the IFUNC resolver is just a declaration. We should perhaps call setCommonAttributes
and getTargetCodeGenInfo().setTargetAttributes
right after the invocation of EmitMultiVersionResolver
where the actual definition of the resolver function is emitted. I've just tried this and the resolver is indeed marked "hidden" with -fvisibility=hidden.
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 usually call setCommonAttributes while we're in the process of emitting the definition, anyway; we don't need the function body for anything. So it's appropriate to call it in the same places we'd call setTargetAttributes().
If you think it would be more clear to move the necessary code somewhere else, that's fine.
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.
When we create the resolver with GetOrCreateLLVMFunction, we construct a GlobalDecl on the spot, and as a result it won't call SetFunctionAttributes because the underlying Decl is nullptr. SetFunctionAttributes is responsible for setting the symbol's visibility and target attributes, therefore it's what we are missing.
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.
Considering calling either SetCommonAttributes
or setGVProperties
, here are the attributes which could be set with some reasonable value of GD
(as I'm not sure if it would be correct to pass through the GD
object corresponding to the function defined in the source code when setting attributes of a synthetic resolver function).
SetCommonAttributes
: Checking for UsedAttr
doesn't make much sense in our case, neither we deal with a variable declaration, thus the only relevant fragment is
const Decl *D = GD.getDecl();
if (isa_and_nonnull<NamedDecl>(D))
setGVProperties(GV, GD);
else
GV->setVisibility(llvm::GlobalValue::DefaultVisibility);
setGVProperties(llvm::GlobalValue *, GlobalDecl)
first calls setDLLImportDLLExport
(irrelevant, as it handles externally-visible declaration) and then setGVPropertiesAux
:
void CodeGenModule::setGVPropertiesAux(llvm::GlobalValue *GV,
const NamedDecl *D) const {
setGlobalVisibility(GV, D);
setDSOLocal(GV);
GV->setPartition(CodeGenOpts.SymbolPartition);
}
The only its callee which uses the NamedDecl *D
argument is setGlobalVisibility(llvm::GlobalValue *, const NamedDecl *)
function that calls GV->setVisibility(...)
with the correct visibility type. Notably, if GV
has local linkage, it is always DefaultVisibility
and D
is not even checked.
Considering the EmitMultiVersionResolver
, it can be called from two places: either emitCPUDispatchDefinition
or emitMultiVersionFunctions
, and in both cases the resolver's linkage is explicitly computed to be either WeakODRLinkage
or InternalLinkage
(see e3b1052).
A proof of concept pushed in 33a92e0
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'd really prefer to share codepaths a bit more... even if it doesn't save any code, having common paths for setting up globals makes future changes to IR a lot easier. If we really can't, though, I guess it's okay.
Visibility doesn't matter for internal functions, but it matters a lot for WeakODRLinkage. I assume we want the resolver to inherit the visibility of the function.
ec1fe0c
to
23a5407
Compare
I have rebased this PR onto current |
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 need this instead as I explained on the other thread.
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 2d37e0f13199..e26a540a8cb4 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4586,6 +4586,8 @@ void CodeGenModule::emitMultiVersionFunctions() {
});
CodeGenFunction CGF(*this);
CGF.EmitMultiVersionResolver(ResolverFunc, Options);
+ SetFunctionAttributes(GD, ResolverFunc, /*IsIncompleteFunction=*/false,
+ /*IsThunk=*/false);
}
// Ensure that any additions to the deferred decls list caused by emitting a
Also a test to check that hidden
is added to the resolver if specified on the commnad line
ping @atrosinenko |
@labrinea I'm sorry for disappearing, I will update this PR this week. |
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.
LGTM
No description provided.