Skip to content

Commit 5195708

Browse files
committed
[AArch64][PAC] Sign block addresses used in indirectbr.
Enabled in clang using: -fptrauth-indirect-gotos and at the IR level using function attribute: "ptrauth-indirect-gotos" Signing uses IA and a per-function integer discriminator. The discriminator isn't ABI-visible, and is currently: ptrauth_string_discriminator("<function_name> blockaddress") A sufficiently sophisticated frontend could benefit from per-indirectbr discrimination, which would need additional machinery, such as allowing "ptrauth" bundles on indirectbr. For our purposes, the simple scheme above is sufficient.
1 parent 4a1fdeb commit 5195708

File tree

20 files changed

+308
-11
lines changed

20 files changed

+308
-11
lines changed

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls)
108108
FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns)
109109
FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination)
110110
FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination)
111+
FEATURE(ptrauth_indirect_gotos, LangOpts.PointerAuthIndirectGotos)
111112
FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls)
112113
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
113114
EXTENSION(swiftcc,

clang/include/clang/Basic/LangOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library fea
165165
LANGOPT(PointerAuthIntrinsics, 1, 0, "pointer authentication intrinsics")
166166
LANGOPT(PointerAuthCalls , 1, 0, "function pointer authentication")
167167
LANGOPT(PointerAuthReturns, 1, 0, "return pointer authentication")
168+
LANGOPT(PointerAuthIndirectGotos, 1, 0, "indirect gotos pointer authentication")
168169
LANGOPT(PointerAuthAuthTraps, 1, 0, "pointer authentication failure traps")
169170
LANGOPT(PointerAuthVTPtrAddressDiscrimination, 1, 0, "incorporate address discrimination in authenticated vtable pointers")
170171
LANGOPT(PointerAuthVTPtrTypeDiscrimination, 1, 0, "incorporate type discrimination in authenticated vtable pointers")

clang/include/clang/Basic/PointerAuthOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ class PointerAuthSchema {
154154
};
155155

156156
struct PointerAuthOptions {
157+
/// Do indirect goto label addresses need to be authenticated?
158+
bool IndirectGotos = false;
159+
157160
/// The ABI for C function pointers.
158161
PointerAuthSchema FunctionPointers;
159162

clang/include/clang/Driver/Options.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4228,6 +4228,8 @@ defm ptrauth_vtable_pointer_address_discrimination :
42284228
defm ptrauth_vtable_pointer_type_discrimination :
42294229
OptInCC1FFlag<"ptrauth-vtable-pointer-type-discrimination", "Enable type discrimination of vtable pointers">;
42304230
defm ptrauth_init_fini : OptInCC1FFlag<"ptrauth-init-fini", "Enable signing of function pointers in init/fini arrays">;
4231+
defm ptrauth_indirect_gotos : OptInCC1FFlag<"ptrauth-indirect-gotos",
4232+
"Enable signing and authentication of indirect goto targets">;
42314233
}
42324234

42334235
def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>,

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
865865
const CodeGenOptions &CodeGenOpts = CGM.getCodeGenOpts();
866866
if (CodeGenOpts.PointerAuth.FunctionPointers)
867867
Fn->addFnAttr("ptrauth-calls");
868+
if (CodeGenOpts.PointerAuth.IndirectGotos)
869+
Fn->addFnAttr("ptrauth-indirect-gotos");
868870

869871
// Apply xray attributes to the function (as a string, for now)
870872
bool AlwaysXRayAttr = false;

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1789,6 +1789,9 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
17891789
options::OPT_fno_ptrauth_vtable_pointer_type_discrimination);
17901790
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_init_fini,
17911791
options::OPT_fno_ptrauth_init_fini);
1792+
1793+
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_indirect_gotos,
1794+
options::OPT_fno_ptrauth_indirect_gotos);
17921795
}
17931796

17941797
void Clang::AddLoongArchTargetArgs(const ArgList &Args,

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1480,13 +1480,14 @@ void CompilerInvocation::setDefaultPointerAuthOptions(
14801480
Opts.CXXVirtualFunctionPointers = Opts.CXXVirtualVariadicFunctionPointers =
14811481
PointerAuthSchema(Key::ASIA, true, Discrimination::Decl);
14821482
}
1483+
Opts.IndirectGotos = LangOpts.PointerAuthIndirectGotos;
14831484
}
14841485

14851486
static void parsePointerAuthOptions(PointerAuthOptions &Opts,
14861487
const LangOptions &LangOpts,
14871488
const llvm::Triple &Triple,
14881489
DiagnosticsEngine &Diags) {
1489-
if (!LangOpts.PointerAuthCalls)
1490+
if (!LangOpts.PointerAuthCalls && !LangOpts.PointerAuthIndirectGotos)
14901491
return;
14911492

14921493
CompilerInvocation::setDefaultPointerAuthOptions(Opts, LangOpts, Triple);
@@ -3390,6 +3391,8 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts,
33903391
GenerateArg(Consumer, OPT_fptrauth_calls);
33913392
if (Opts.PointerAuthReturns)
33923393
GenerateArg(Consumer, OPT_fptrauth_returns);
3394+
if (Opts.PointerAuthIndirectGotos)
3395+
GenerateArg(Consumer, OPT_fptrauth_indirect_gotos);
33933396
if (Opts.PointerAuthAuthTraps)
33943397
GenerateArg(Consumer, OPT_fptrauth_auth_traps);
33953398
if (Opts.PointerAuthVTPtrAddressDiscrimination)
@@ -3405,6 +3408,7 @@ static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
34053408
Opts.PointerAuthIntrinsics = Args.hasArg(OPT_fptrauth_intrinsics);
34063409
Opts.PointerAuthCalls = Args.hasArg(OPT_fptrauth_calls);
34073410
Opts.PointerAuthReturns = Args.hasArg(OPT_fptrauth_returns);
3411+
Opts.PointerAuthIndirectGotos = Args.hasArg(OPT_fptrauth_indirect_gotos);
34083412
Opts.PointerAuthAuthTraps = Args.hasArg(OPT_fptrauth_auth_traps);
34093413
Opts.PointerAuthVTPtrAddressDiscrimination =
34103414
Args.hasArg(OPT_fptrauth_vtable_pointer_address_discrimination);

clang/test/CodeGen/ptrauth-function-attributes.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,CALLS
55
// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,CALLS
66

7+
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-indirect-gotos -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,GOTOS
8+
// RUN: %clang_cc1 -triple arm64e-apple-ios -fptrauth-indirect-gotos -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,GOTOS
9+
710
// ALL: define {{(dso_local )?}}void @test() #0
811
void test() {
912
}
1013

1114
// CALLS: attributes #0 = {{{.*}} "ptrauth-calls" {{.*}}}
1215

16+
// GOTOS: attributes #0 = {{{.*}} "ptrauth-indirect-gotos" {{.*}}}
17+
1318
// OFF-NOT: attributes {{.*}} "ptrauth-

llvm/docs/PointerAuth.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ At the IR level, it is represented using:
1818
* a [set of intrinsics](#intrinsics) (to sign/authenticate pointers)
1919
* a [signed pointer constant](#constant) (to sign globals)
2020
* a [call operand bundle](#operand-bundle) (to authenticate called pointers)
21+
* a [set of function attributes](#function-attributes) (to describe what
22+
pointers are signed and how, to control implicit codegen in the backend, as
23+
well as preserve invariants in the mid-level optimizer)
2124

2225
The current implementation leverages the
2326
[Armv8.3-A PAuth/Pointer Authentication Code](#armv8-3-a-pauth-pointer-authentication-code)
@@ -287,6 +290,27 @@ but with the added guarantee that `%fp_i`, `%fp_auth`, and `%fp_auth_p`
287290
are not stored to (and reloaded from) memory.
288291

289292

293+
### Function Attributes
294+
295+
Some function attributes are used to describe other pointer authentication
296+
operations that are not otherwise explicitly expressed in IR.
297+
298+
#### ``ptrauth-indirect-gotos``
299+
300+
``ptrauth-indirect-gotos`` specifies that indirect gotos in this function
301+
should authenticate their target. At the IR level, no other change is needed.
302+
When lowering [``blockaddress`` constants](https://llvm.org/docs/LangRef.html#blockaddress),
303+
and [``indirectbr`` instructions](https://llvm.org/docs/LangRef.html#i-indirectbr),
304+
this tells the backend to respectively sign and authenticate the pointers.
305+
306+
The specific scheme isn't ABI-visible. Currently, the AArch64 backend
307+
signs blockaddresses using the `ASIA` key, with an integer discriminator
308+
derived from the parent function's name, using the SipHash stable discriminator:
309+
```
310+
ptrauth_string_discriminator("<function_name> blockaddress")
311+
```
312+
313+
290314
## AArch64 Support
291315

292316
AArch64 is currently the only architecture with full support of the pointer

llvm/include/llvm/CodeGen/AsmPrinter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,9 @@ class AsmPrinter : public MachineFunctionPass {
577577
report_fatal_error("ptrauth constant lowering not implemented");
578578
}
579579

580+
/// Lower the specified BlockAddress to an MCExpr.
581+
virtual const MCExpr *lowerBlockAddressConstant(const BlockAddress &BA);
582+
580583
/// Return true if the basic block has exactly one predecessor and the control
581584
/// transfer mechanism between the predecessor and this block is a
582585
/// fall-through.

0 commit comments

Comments
 (0)