Skip to content

Commit 016baec

Browse files
ahatanakrjmccall
authored andcommitted
[clang] Implement function pointer signing.
Co-Authored-By: John McCall <[email protected]>
1 parent 7c814c1 commit 016baec

23 files changed

+632
-17
lines changed

clang/include/clang/Basic/CodeGenOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef LLVM_CLANG_BASIC_CODEGENOPTIONS_H
1414
#define LLVM_CLANG_BASIC_CODEGENOPTIONS_H
1515

16+
#include "clang/Basic/PointerAuthOptions.h"
1617
#include "clang/Basic/Sanitizers.h"
1718
#include "clang/Basic/XRayInstr.h"
1819
#include "llvm/ADT/FloatingPointMode.h"
@@ -391,6 +392,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
391392

392393
std::vector<std::string> Reciprocals;
393394

395+
/// Configuration for pointer-signing.
396+
PointerAuthOptions PointerAuth;
397+
394398
/// The preferred width for auto-vectorization transforms. This is intended to
395399
/// override default transforms based on the width of the architected vector
396400
/// registers.

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,9 @@ def err_drv_omp_host_ir_file_not_found : Error<
351351
"target regions but cannot be found">;
352352
def err_drv_omp_host_target_not_supported : Error<
353353
"target '%0' is not a supported OpenMP host target">;
354+
def err_drv_ptrauth_not_supported : Error<
355+
"target '%0' does not support native pointer authentication">;
356+
354357
def err_drv_expecting_fopenmp_with_fopenmp_targets : Error<
355358
"'-fopenmp-targets' must be used in conjunction with a '-fopenmp' option "
356359
"compatible with offloading; e.g., '-fopenmp=libomp' or '-fopenmp=libiomp5'">;

clang/include/clang/Basic/LangOptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,8 @@ class LangOptionsBase {
346346
BKey
347347
};
348348

349+
using PointerAuthenticationMode = ::clang::PointerAuthenticationMode;
350+
349351
enum class ThreadModelKind {
350352
/// POSIX Threads.
351353
POSIX,

clang/include/clang/Basic/PointerAuthOptions.h

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,146 @@
1414
#ifndef LLVM_CLANG_BASIC_POINTERAUTHOPTIONS_H
1515
#define LLVM_CLANG_BASIC_POINTERAUTHOPTIONS_H
1616

17+
#include "clang/Basic/LLVM.h"
18+
#include "clang/Basic/LangOptions.h"
19+
#include "llvm/Support/ErrorHandling.h"
20+
#include "llvm/Target/TargetOptions.h"
21+
#include <map>
22+
#include <memory>
23+
#include <string>
24+
#include <vector>
25+
1726
namespace clang {
1827

1928
constexpr unsigned PointerAuthKeyNone = -1;
2029

30+
class PointerAuthSchema {
31+
public:
32+
enum class Kind : unsigned {
33+
None,
34+
ARM8_3,
35+
};
36+
37+
/// Hardware pointer-signing keys in ARM8.3.
38+
///
39+
/// These values are the same used in ptrauth.h.
40+
enum class ARM8_3Key : unsigned {
41+
ASIA = 0,
42+
ASIB = 1,
43+
ASDA = 2,
44+
ASDB = 3
45+
};
46+
47+
/// Forms of extra discrimination.
48+
enum class Discrimination : unsigned {
49+
/// No additional discrimination.
50+
None,
51+
52+
/// Discriminate using a constant value.
53+
Constant,
54+
};
55+
56+
private:
57+
Kind TheKind : 2;
58+
unsigned IsAddressDiscriminated : 1;
59+
unsigned IsIsaPointer : 1;
60+
unsigned AuthenticatesNullValues : 1;
61+
PointerAuthenticationMode SelectedAuthenticationMode : 2;
62+
Discrimination DiscriminationKind : 2;
63+
unsigned Key : 4;
64+
unsigned ConstantDiscriminator : 16;
65+
66+
public:
67+
PointerAuthSchema() : TheKind(Kind::None) {}
68+
69+
PointerAuthSchema(
70+
ARM8_3Key Key, bool IsAddressDiscriminated,
71+
PointerAuthenticationMode AuthenticationMode,
72+
Discrimination OtherDiscrimination,
73+
std::optional<uint16_t> ConstantDiscriminatorOrNone = std::nullopt,
74+
bool IsIsaPointer = false, bool AuthenticatesNullValues = false)
75+
: TheKind(Kind::ARM8_3), IsAddressDiscriminated(IsAddressDiscriminated),
76+
IsIsaPointer(IsIsaPointer),
77+
AuthenticatesNullValues(AuthenticatesNullValues),
78+
SelectedAuthenticationMode(AuthenticationMode),
79+
DiscriminationKind(OtherDiscrimination), Key(unsigned(Key)) {
80+
assert((getOtherDiscrimination() != Discrimination::Constant ||
81+
ConstantDiscriminatorOrNone) &&
82+
"constant discrimination requires a constant!");
83+
if (ConstantDiscriminatorOrNone)
84+
ConstantDiscriminator = *ConstantDiscriminatorOrNone;
85+
}
86+
87+
PointerAuthSchema(
88+
ARM8_3Key Key, bool IsAddressDiscriminated,
89+
Discrimination OtherDiscrimination,
90+
std::optional<uint16_t> ConstantDiscriminatorOrNone = std::nullopt,
91+
bool IsIsaPointer = false, bool AuthenticatesNullValues = false)
92+
: PointerAuthSchema(Key, IsAddressDiscriminated,
93+
PointerAuthenticationMode::SignAndAuth,
94+
OtherDiscrimination, ConstantDiscriminatorOrNone,
95+
IsIsaPointer, AuthenticatesNullValues) {}
96+
97+
Kind getKind() const { return TheKind; }
98+
99+
explicit operator bool() const { return isEnabled(); }
100+
101+
bool isEnabled() const { return getKind() != Kind::None; }
102+
103+
bool isAddressDiscriminated() const {
104+
assert(getKind() != Kind::None);
105+
return IsAddressDiscriminated;
106+
}
107+
108+
bool isIsaPointer() const {
109+
assert(getKind() != Kind::None);
110+
return IsIsaPointer;
111+
}
112+
113+
bool authenticatesNullValues() const {
114+
assert(getKind() != Kind::None);
115+
return AuthenticatesNullValues;
116+
}
117+
118+
bool hasOtherDiscrimination() const {
119+
return getOtherDiscrimination() != Discrimination::None;
120+
}
121+
122+
Discrimination getOtherDiscrimination() const {
123+
assert(getKind() != Kind::None);
124+
return DiscriminationKind;
125+
}
126+
127+
uint16_t getConstantDiscrimination() const {
128+
assert(getOtherDiscrimination() == Discrimination::Constant);
129+
return (uint16_t)ConstantDiscriminator;
130+
}
131+
132+
unsigned getKey() const {
133+
switch (getKind()) {
134+
case Kind::None:
135+
llvm_unreachable("calling getKey() on disabled schema");
136+
case Kind::ARM8_3:
137+
return unsigned(getARM8_3Key());
138+
}
139+
llvm_unreachable("bad key kind");
140+
}
141+
142+
PointerAuthenticationMode getAuthenticationMode() const {
143+
return SelectedAuthenticationMode;
144+
}
145+
146+
ARM8_3Key getARM8_3Key() const {
147+
assert(getKind() == Kind::ARM8_3);
148+
return ARM8_3Key(Key);
149+
}
150+
};
151+
152+
struct PointerAuthOptions {
153+
/// The ABI for C function pointers.
154+
PointerAuthSchema FunctionPointers;
155+
};
156+
21157
} // end namespace clang
22158

23159
#endif

clang/include/clang/Frontend/CompilerInvocation.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,16 @@ class CompilerInvocation : public CompilerInvocationBase {
305305
/// executable), for finding the builtin compiler path.
306306
static std::string GetResourcesPath(const char *Argv0, void *MainAddr);
307307

308+
/// Populate \p Opts with the default set of pointer authentication-related
309+
/// options given \p LangOpts and \p Triple. Return true if defaults are
310+
/// available.
311+
///
312+
/// Note: This is intended to be used by tools which must be aware of
313+
/// pointer authentication-related code generation, e.g. lldb.
314+
static bool setDefaultPointerAuthOptions(PointerAuthOptions &Opts,
315+
const LangOptions &LangOpts,
316+
const llvm::Triple &Triple);
317+
308318
/// Retrieve a module hash string that is suitable for uniquely
309319
/// identifying the conditions under which the module was built.
310320
std::string getModuleHash() const;

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6015,8 +6015,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
60156015
// If this is a predefined lib function (e.g. malloc), emit the call
60166016
// using exactly the normal call path.
60176017
if (getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID))
6018-
return emitLibraryCall(
6019-
*this, FD, E, cast<llvm::Constant>(EmitScalarExpr(E->getCallee())));
6018+
return emitLibraryCall(*this, FD, E, CGM.getRawFunctionPointer(FD));
60206019

60216020
// Check that a call to a target specific builtin has the correct target
60226021
// features.

clang/lib/CodeGen/CGCall.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5678,6 +5678,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
56785678
!isa_and_nonnull<FunctionDecl>(TargetDecl))
56795679
EmitKCFIOperandBundle(ConcreteCallee, BundleList);
56805680

5681+
// Add the pointer-authentication bundle.
5682+
EmitPointerAuthOperandBundle(ConcreteCallee.getPointerAuthInfo(), BundleList);
5683+
56815684
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl))
56825685
if (FD->hasAttr<StrictFPAttr>())
56835686
// All calls within a strictfp function are marked strictfp

clang/lib/CodeGen/CGCall.h

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef LLVM_CLANG_LIB_CODEGEN_CGCALL_H
1515
#define LLVM_CLANG_LIB_CODEGEN_CGCALL_H
1616

17+
#include "CGPointerAuthInfo.h"
1718
#include "CGValue.h"
1819
#include "EHScopeStack.h"
1920
#include "clang/AST/ASTFwd.h"
@@ -69,6 +70,10 @@ class CGCallee {
6970
Last = Virtual
7071
};
7172

73+
struct OrdinaryInfoStorage {
74+
CGCalleeInfo AbstractInfo;
75+
CGPointerAuthInfo PointerAuthInfo;
76+
};
7277
struct BuiltinInfoStorage {
7378
const FunctionDecl *Decl;
7479
unsigned ID;
@@ -85,7 +90,7 @@ class CGCallee {
8590

8691
SpecialKind KindOrFunctionPointer;
8792
union {
88-
CGCalleeInfo AbstractInfo;
93+
OrdinaryInfoStorage OrdinaryInfo;
8994
BuiltinInfoStorage BuiltinInfo;
9095
PseudoDestructorInfoStorage PseudoDestructorInfo;
9196
VirtualInfoStorage VirtualInfo;
@@ -104,10 +109,13 @@ class CGCallee {
104109

105110
/// Construct a callee. Call this constructor directly when this
106111
/// isn't a direct call.
107-
CGCallee(const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr)
112+
CGCallee(
113+
const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr,
114+
const CGPointerAuthInfo &pointerAuthInfo = /*FIXME*/ CGPointerAuthInfo())
108115
: KindOrFunctionPointer(
109116
SpecialKind(reinterpret_cast<uintptr_t>(functionPtr))) {
110-
AbstractInfo = abstractInfo;
117+
OrdinaryInfo.AbstractInfo = abstractInfo;
118+
OrdinaryInfo.PointerAuthInfo = pointerAuthInfo;
111119
assert(functionPtr && "configuring callee without function pointer");
112120
assert(functionPtr->getType()->isPointerTy());
113121
}
@@ -128,12 +136,12 @@ class CGCallee {
128136

129137
static CGCallee forDirect(llvm::Constant *functionPtr,
130138
const CGCalleeInfo &abstractInfo = CGCalleeInfo()) {
131-
return CGCallee(abstractInfo, functionPtr);
139+
return CGCallee(abstractInfo, functionPtr, CGPointerAuthInfo());
132140
}
133141

134142
static CGCallee forDirect(llvm::FunctionCallee functionPtr,
135143
const CGCalleeInfo &abstractInfo = CGCalleeInfo()) {
136-
return CGCallee(abstractInfo, functionPtr.getCallee());
144+
return CGCallee(abstractInfo, functionPtr.getCallee(), CGPointerAuthInfo());
137145
}
138146

139147
static CGCallee forVirtual(const CallExpr *CE, GlobalDecl MD, Address Addr,
@@ -173,7 +181,11 @@ class CGCallee {
173181
if (isVirtual())
174182
return VirtualInfo.MD;
175183
assert(isOrdinary());
176-
return AbstractInfo;
184+
return OrdinaryInfo.AbstractInfo;
185+
}
186+
const CGPointerAuthInfo &getPointerAuthInfo() const {
187+
assert(isOrdinary());
188+
return OrdinaryInfo.PointerAuthInfo;
177189
}
178190
llvm::Value *getFunctionPointer() const {
179191
assert(isOrdinary());
@@ -184,6 +196,10 @@ class CGCallee {
184196
KindOrFunctionPointer =
185197
SpecialKind(reinterpret_cast<uintptr_t>(functionPtr));
186198
}
199+
void setPointerAuthInfo(CGPointerAuthInfo pointerAuth) {
200+
assert(isOrdinary());
201+
OrdinaryInfo.PointerAuthInfo = pointerAuth;
202+
}
187203

188204
bool isVirtual() const {
189205
return KindOrFunctionPointer == SpecialKind::Virtual;

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2856,22 +2856,22 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
28562856
return LV;
28572857
}
28582858

2859-
static llvm::Constant *EmitFunctionDeclPointer(CodeGenModule &CGM,
2860-
GlobalDecl GD) {
2859+
llvm::Constant *CodeGenModule::getRawFunctionPointer(GlobalDecl GD,
2860+
llvm::Type *Ty) {
28612861
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
28622862
if (FD->hasAttr<WeakRefAttr>()) {
2863-
ConstantAddress aliasee = CGM.GetWeakRefReference(FD);
2863+
ConstantAddress aliasee = GetWeakRefReference(FD);
28642864
return aliasee.getPointer();
28652865
}
28662866

2867-
llvm::Constant *V = CGM.GetAddrOfFunction(GD);
2867+
llvm::Constant *V = GetAddrOfFunction(GD, Ty);
28682868
return V;
28692869
}
28702870

28712871
static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF, const Expr *E,
28722872
GlobalDecl GD) {
28732873
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
2874-
llvm::Value *V = EmitFunctionDeclPointer(CGF.CGM, GD);
2874+
llvm::Constant *V = CGF.CGM.getFunctionPointer(GD);
28752875
CharUnits Alignment = CGF.getContext().getDeclAlign(FD);
28762876
return CGF.MakeAddrLValue(V, E->getType(), Alignment,
28772877
AlignmentSource::Decl);
@@ -5506,7 +5506,7 @@ static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) {
55065506
// name to make it clear it's not the actual builtin.
55075507
if (CGF.CurFn->getName() != FDInlineName &&
55085508
OnlyHasInlineBuiltinDeclaration(FD)) {
5509-
llvm::Constant *CalleePtr = EmitFunctionDeclPointer(CGF.CGM, GD);
5509+
llvm::Constant *CalleePtr = CGF.CGM.getRawFunctionPointer(GD);
55105510
llvm::Function *Fn = llvm::cast<llvm::Function>(CalleePtr);
55115511
llvm::Module *M = Fn->getParent();
55125512
llvm::Function *Clone = M->getFunction(FDInlineName);
@@ -5529,7 +5529,7 @@ static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) {
55295529
return CGCallee::forBuiltin(builtinID, FD);
55305530
}
55315531

5532-
llvm::Constant *CalleePtr = EmitFunctionDeclPointer(CGF.CGM, GD);
5532+
llvm::Constant *CalleePtr = CGF.CGM.getRawFunctionPointer(GD);
55335533
if (CGF.CGM.getLangOpts().CUDA && !CGF.CGM.getLangOpts().CUDAIsDevice &&
55345534
FD->hasAttr<CUDAGlobalAttr>())
55355535
CalleePtr = CGF.CGM.getCUDARuntime().getKernelStub(
@@ -5586,7 +5586,8 @@ CGCallee CodeGenFunction::EmitCallee(const Expr *E) {
55865586
GD = GlobalDecl(VD);
55875587

55885588
CGCalleeInfo calleeInfo(functionType->getAs<FunctionProtoType>(), GD);
5589-
CGCallee callee(calleeInfo, calleePtr);
5589+
CGPointerAuthInfo pointerAuth = CGM.getFunctionPointerAuthInfo(functionType);
5590+
CGCallee callee(calleeInfo, calleePtr, pointerAuth);
55905591
return callee;
55915592
}
55925593

clang/lib/CodeGen/CGExprConstant.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2024,8 +2024,25 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
20242024
if (D->hasAttr<WeakRefAttr>())
20252025
return CGM.GetWeakRefReference(D).getPointer();
20262026

2027+
auto PtrAuthSign = [&](llvm::Constant *C) {
2028+
CGPointerAuthInfo AuthInfo = CGM.getFunctionPointerAuthInfo(DestType);
2029+
2030+
if (AuthInfo) {
2031+
if (hasNonZeroOffset())
2032+
return ConstantLValue(nullptr);
2033+
2034+
C = applyOffset(C);
2035+
C = CGM.getConstantSignedPointer(
2036+
C, AuthInfo.getKey(), nullptr,
2037+
cast_or_null<llvm::Constant>(AuthInfo.getDiscriminator()));
2038+
return ConstantLValue(C, /*applied offset*/ true);
2039+
}
2040+
2041+
return ConstantLValue(C);
2042+
};
2043+
20272044
if (auto FD = dyn_cast<FunctionDecl>(D))
2028-
return CGM.GetAddrOfFunction(FD);
2045+
return PtrAuthSign(CGM.getRawFunctionPointer(FD));
20292046

20302047
if (auto VD = dyn_cast<VarDecl>(D)) {
20312048
// We can never refer to a variable with local storage.

0 commit comments

Comments
 (0)