Skip to content

Commit c2c6b06

Browse files
ahmedbougachayuxuanchen1997
authored andcommitted
[AArch64][PAC] Sign block addresses used in indirectbr. (#97647)
Summary: 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. This approach doesn't support subtracting label addresses and using the result as offsets, because each label address is signed. Pointer arithmetic on signed pointers corrupts the signature bits, and because label address expressions aren't typed beyond void*, we can't do anything reliably intelligent on the arithmetic exprs. Not signing addresses when used to form offsets would allow easily hijacking control flow by overwriting the offset. This diagnoses the basic cases (`&&lbl2 - &&lbl1`) in the frontend, while we evaluate either alternative implementations (e.g., lowering blockaddress to a bb number, and indirectbr to a checked jump-table), or better diagnostics (both at the frontend level and on unencodable IR constants). Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60251245
1 parent 0a7aeb1 commit c2c6b06

23 files changed

+498
-11
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,9 @@ def note_ptrauth_virtual_function_pointer_incomplete_arg_ret :
949949
def note_ptrauth_virtual_function_incomplete_arg_ret_type :
950950
Note<"%0 is incomplete">;
951951

952+
def err_ptrauth_indirect_goto_addrlabel_arithmetic : Error<
953+
"%select{subtraction|addition}0 of address-of-label expressions is not "
954+
"supported with ptrauth indirect gotos">;
952955

953956
/// main()
954957
// static main() is not an error in C, just in C++.

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ FEATURE(ptrauth_type_info_vtable_pointer_discrimination, LangOpts.PointerAuthTyp
112112
FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls)
113113
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
114114
FEATURE(ptrauth_function_pointer_type_discrimination, LangOpts.PointerAuthFunctionTypeDiscrimination)
115+
FEATURE(ptrauth_indirect_gotos, LangOpts.PointerAuthIndirectGotos)
115116
EXTENSION(swiftcc,
116117
PP.getTargetInfo().checkCallingConvention(CC_Swift) ==
117118
clang::TargetInfo::CCCR_OK)

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
@@ -159,6 +159,9 @@ class PointerAuthSchema {
159159
};
160160

161161
struct PointerAuthOptions {
162+
/// Do indirect goto label addresses need to be authenticated?
163+
bool IndirectGotos = false;
164+
162165
/// The ABI for C function pointers.
163166
PointerAuthSchema FunctionPointers;
164167

clang/include/clang/Driver/Options.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4254,6 +4254,8 @@ defm ptrauth_type_info_vtable_pointer_discrimination :
42544254
defm ptrauth_init_fini : OptInCC1FFlag<"ptrauth-init-fini", "Enable signing of function pointers in init/fini arrays">;
42554255
defm ptrauth_function_pointer_type_discrimination : OptInCC1FFlag<"ptrauth-function-pointer-type-discrimination",
42564256
"Enable type discrimination on C function pointers">;
4257+
defm ptrauth_indirect_gotos : OptInCC1FFlag<"ptrauth-indirect-gotos",
4258+
"Enable signing and authentication of indirect goto targets">;
42574259
}
42584260

42594261
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
@@ -882,6 +882,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
882882
const CodeGenOptions &CodeGenOpts = CGM.getCodeGenOpts();
883883
if (CodeGenOpts.PointerAuth.FunctionPointers)
884884
Fn->addFnAttr("ptrauth-calls");
885+
if (CodeGenOpts.PointerAuth.IndirectGotos)
886+
Fn->addFnAttr("ptrauth-indirect-gotos");
885887

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

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1848,6 +1848,9 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
18481848
Args.addOptInFlag(
18491849
CmdArgs, options::OPT_fptrauth_function_pointer_type_discrimination,
18501850
options::OPT_fno_ptrauth_function_pointer_type_discrimination);
1851+
1852+
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_indirect_gotos,
1853+
options::OPT_fno_ptrauth_indirect_gotos);
18511854
}
18521855

18531856
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
@@ -1504,13 +1504,14 @@ void CompilerInvocation::setDefaultPointerAuthOptions(
15041504
Opts.CXXMemberFunctionPointers =
15051505
PointerAuthSchema(Key::ASIA, false, Discrimination::Type);
15061506
}
1507+
Opts.IndirectGotos = LangOpts.PointerAuthIndirectGotos;
15071508
}
15081509

15091510
static void parsePointerAuthOptions(PointerAuthOptions &Opts,
15101511
const LangOptions &LangOpts,
15111512
const llvm::Triple &Triple,
15121513
DiagnosticsEngine &Diags) {
1513-
if (!LangOpts.PointerAuthCalls)
1514+
if (!LangOpts.PointerAuthCalls && !LangOpts.PointerAuthIndirectGotos)
15141515
return;
15151516

15161517
CompilerInvocation::setDefaultPointerAuthOptions(Opts, LangOpts, Triple);
@@ -3414,6 +3415,8 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts,
34143415
GenerateArg(Consumer, OPT_fptrauth_calls);
34153416
if (Opts.PointerAuthReturns)
34163417
GenerateArg(Consumer, OPT_fptrauth_returns);
3418+
if (Opts.PointerAuthIndirectGotos)
3419+
GenerateArg(Consumer, OPT_fptrauth_indirect_gotos);
34173420
if (Opts.PointerAuthAuthTraps)
34183421
GenerateArg(Consumer, OPT_fptrauth_auth_traps);
34193422
if (Opts.PointerAuthVTPtrAddressDiscrimination)
@@ -3434,6 +3437,7 @@ static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
34343437
Opts.PointerAuthIntrinsics = Args.hasArg(OPT_fptrauth_intrinsics);
34353438
Opts.PointerAuthCalls = Args.hasArg(OPT_fptrauth_calls);
34363439
Opts.PointerAuthReturns = Args.hasArg(OPT_fptrauth_returns);
3440+
Opts.PointerAuthIndirectGotos = Args.hasArg(OPT_fptrauth_indirect_gotos);
34373441
Opts.PointerAuthAuthTraps = Args.hasArg(OPT_fptrauth_auth_traps);
34383442
Opts.PointerAuthVTPtrAddressDiscrimination =
34393443
Args.hasArg(OPT_fptrauth_vtable_pointer_address_discrimination);

clang/lib/Sema/SemaExpr.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10909,6 +10909,14 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
1090910909
if (isObjCPointer && checkArithmeticOnObjCPointer(*this, Loc, PExp))
1091010910
return QualType();
1091110911

10912+
// Arithmetic on label addresses is normally allowed, except when we add
10913+
// a ptrauth signature to the addresses.
10914+
if (isa<AddrLabelExpr>(PExp) && getLangOpts().PointerAuthIndirectGotos) {
10915+
Diag(Loc, diag::err_ptrauth_indirect_goto_addrlabel_arithmetic)
10916+
<< /*addition*/ 1;
10917+
return QualType();
10918+
}
10919+
1091210920
// Check array bounds for pointer arithemtic
1091310921
CheckArrayAccess(PExp, IExp);
1091410922

@@ -10983,6 +10991,15 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
1098310991
checkArithmeticOnObjCPointer(*this, Loc, LHS.get()))
1098410992
return QualType();
1098510993

10994+
// Arithmetic on label addresses is normally allowed, except when we add
10995+
// a ptrauth signature to the addresses.
10996+
if (isa<AddrLabelExpr>(LHS.get()) &&
10997+
getLangOpts().PointerAuthIndirectGotos) {
10998+
Diag(Loc, diag::err_ptrauth_indirect_goto_addrlabel_arithmetic)
10999+
<< /*subtraction*/ 0;
11000+
return QualType();
11001+
}
11002+
1098611003
// The result type of a pointer-int computation is the pointer type.
1098711004
if (RHS.get()->getType()->isIntegerType()) {
1098811005
// Subtracting from a null pointer should produce a warning.

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-

0 commit comments

Comments
 (0)