Skip to content

Commit 7c814c1

Browse files
[clang] Define ptrauth_sign_constant builtin. (llvm#93904)
This is a constant-expression equivalent to ptrauth_sign_unauthenticated. Its constant nature lets us guarantee a non-attackable sequence is generated, unlike ptrauth_sign_unauthenticated which we generally discourage using. It being a constant also allows its usage in global initializers, though requiring constant pointers and discriminators. The value must be a constant expression of pointer type which evaluates to a non-null pointer. The key must be a constant expression of type ptrauth_key. The extra data must be a constant expression of pointer or integer type; if an integer, it will be coerced to ptrauth_extra_data_t. The result will have the same type as the original value. This can be used in constant expressions. Co-authored-by: John McCall <[email protected]>
1 parent 50b9193 commit 7c814c1

14 files changed

+395
-15
lines changed

clang/docs/PointerAuthentication.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,25 @@ Given that ``signedPointer`` matches the layout for signed pointers signed with
356356
the given key, extract the raw pointer from it. This operation does not trap
357357
and cannot fail, even if the pointer is not validly signed.
358358

359+
``ptrauth_sign_constant``
360+
^^^^^^^^^^^^^^^^^^^^^^^^^
361+
362+
.. code-block:: c
363+
364+
ptrauth_sign_constant(pointer, key, discriminator)
365+
366+
Return a signed pointer for a constant address in a manner which guarantees
367+
a non-attackable sequence.
368+
369+
``pointer`` must be a constant expression of pointer type which evaluates to
370+
a non-null pointer.
371+
``key`` must be a constant expression of type ``ptrauth_key``.
372+
``discriminator`` must be a constant expression of pointer or integer type;
373+
if an integer, it will be coerced to ``ptrauth_extra_data_t``.
374+
The result will have the same type as ``pointer``.
375+
376+
This can be used in constant expressions.
377+
359378
``ptrauth_sign_unauthenticated``
360379
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
361380

clang/include/clang/Basic/Builtins.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4393,6 +4393,12 @@ def PtrauthSignUnauthenticated : Builtin {
43934393
let Prototype = "void*(void*,int,void*)";
43944394
}
43954395

4396+
def PtrauthSignConstant : Builtin {
4397+
let Spellings = ["__builtin_ptrauth_sign_constant"];
4398+
let Attributes = [CustomTypeChecking, NoThrow, Const, Constexpr];
4399+
let Prototype = "void*(void*,int,void*)";
4400+
}
4401+
43964402
def PtrauthSignGenericData : Builtin {
43974403
let Spellings = ["__builtin_ptrauth_sign_generic_data"];
43984404
let Attributes = [CustomTypeChecking, NoThrow, Const];

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,13 @@ def err_ptrauth_value_bad_type :
924924
Error<"%select{signed value|extra discriminator|blended pointer|blended "
925925
"integer}0 must have %select{pointer|integer|pointer or integer}1 "
926926
"type; type here is %2">;
927+
def err_ptrauth_bad_constant_pointer :
928+
Error<"argument to ptrauth_sign_constant must refer to a global variable "
929+
"or function">;
930+
def err_ptrauth_bad_constant_discriminator :
931+
Error<"discriminator argument to ptrauth_sign_constant must be a constant "
932+
"integer, the address of the global variable where the result "
933+
"will be stored, or a blend of the two">;
927934
def warn_ptrauth_sign_null_pointer :
928935
Warning<"signing a null pointer will yield a non-null pointer">,
929936
InGroup<PtrAuthNullPointers>;

clang/lib/AST/ExprConstant.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2042,6 +2042,7 @@ static bool IsNoOpCall(const CallExpr *E) {
20422042
unsigned Builtin = E->getBuiltinCallee();
20432043
return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
20442044
Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
2045+
Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
20452046
Builtin == Builtin::BI__builtin_function_start);
20462047
}
20472048

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5293,6 +5293,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
52935293
case Builtin::BI__iso_volatile_store64:
52945294
return RValue::get(EmitISOVolatileStore(*this, E));
52955295

5296+
case Builtin::BI__builtin_ptrauth_sign_constant:
5297+
return RValue::get(ConstantEmitter(*this).emitAbstract(E, E->getType()));
5298+
52965299
case Builtin::BI__builtin_ptrauth_auth:
52975300
case Builtin::BI__builtin_ptrauth_auth_and_resign:
52985301
case Builtin::BI__builtin_ptrauth_blend_discriminator:

clang/lib/CodeGen/CGExprConstant.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,6 +1924,12 @@ class ConstantLValueEmitter : public ConstStmtVisitor<ConstantLValueEmitter,
19241924
ConstantLValue VisitMaterializeTemporaryExpr(
19251925
const MaterializeTemporaryExpr *E);
19261926

1927+
ConstantLValue emitPointerAuthSignConstant(const CallExpr *E);
1928+
llvm::Constant *emitPointerAuthPointer(const Expr *E);
1929+
unsigned emitPointerAuthKey(const Expr *E);
1930+
std::pair<llvm::Constant *, llvm::ConstantInt *>
1931+
emitPointerAuthDiscriminator(const Expr *E);
1932+
19271933
bool hasNonZeroOffset() const {
19281934
return !Value.getLValueOffset().isZero();
19291935
}
@@ -2116,6 +2122,10 @@ ConstantLValueEmitter::VisitCallExpr(const CallExpr *E) {
21162122
if (builtin == Builtin::BI__builtin_function_start)
21172123
return CGM.GetFunctionStart(
21182124
E->getArg(0)->getAsBuiltinConstantDeclRef(CGM.getContext()));
2125+
2126+
if (builtin == Builtin::BI__builtin_ptrauth_sign_constant)
2127+
return emitPointerAuthSignConstant(E);
2128+
21192129
if (builtin != Builtin::BI__builtin___CFStringMakeConstantString &&
21202130
builtin != Builtin::BI__builtin___NSStringMakeConstantString)
21212131
return nullptr;
@@ -2129,6 +2139,55 @@ ConstantLValueEmitter::VisitCallExpr(const CallExpr *E) {
21292139
}
21302140
}
21312141

2142+
ConstantLValue
2143+
ConstantLValueEmitter::emitPointerAuthSignConstant(const CallExpr *E) {
2144+
llvm::Constant *UnsignedPointer = emitPointerAuthPointer(E->getArg(0));
2145+
unsigned Key = emitPointerAuthKey(E->getArg(1));
2146+
auto [StorageAddress, OtherDiscriminator] =
2147+
emitPointerAuthDiscriminator(E->getArg(2));
2148+
2149+
llvm::Constant *SignedPointer = CGM.getConstantSignedPointer(
2150+
UnsignedPointer, Key, StorageAddress, OtherDiscriminator);
2151+
return SignedPointer;
2152+
}
2153+
2154+
llvm::Constant *ConstantLValueEmitter::emitPointerAuthPointer(const Expr *E) {
2155+
Expr::EvalResult Result;
2156+
bool Succeeded = E->EvaluateAsRValue(Result, CGM.getContext());
2157+
assert(Succeeded);
2158+
(void)Succeeded;
2159+
2160+
// The assertions here are all checked by Sema.
2161+
assert(Result.Val.isLValue());
2162+
return ConstantEmitter(CGM, Emitter.CGF)
2163+
.emitAbstract(E->getExprLoc(), Result.Val, E->getType());
2164+
}
2165+
2166+
unsigned ConstantLValueEmitter::emitPointerAuthKey(const Expr *E) {
2167+
return E->EvaluateKnownConstInt(CGM.getContext()).getZExtValue();
2168+
}
2169+
2170+
std::pair<llvm::Constant *, llvm::ConstantInt *>
2171+
ConstantLValueEmitter::emitPointerAuthDiscriminator(const Expr *E) {
2172+
E = E->IgnoreParens();
2173+
2174+
if (const auto *Call = dyn_cast<CallExpr>(E)) {
2175+
if (Call->getBuiltinCallee() ==
2176+
Builtin::BI__builtin_ptrauth_blend_discriminator) {
2177+
llvm::Constant *Pointer = ConstantEmitter(CGM).emitAbstract(
2178+
Call->getArg(0), Call->getArg(0)->getType());
2179+
auto *Extra = cast<llvm::ConstantInt>(ConstantEmitter(CGM).emitAbstract(
2180+
Call->getArg(1), Call->getArg(1)->getType()));
2181+
return {Pointer, Extra};
2182+
}
2183+
}
2184+
2185+
llvm::Constant *Result = ConstantEmitter(CGM).emitAbstract(E, E->getType());
2186+
if (Result->getType()->isPointerTy())
2187+
return {Result, nullptr};
2188+
return {nullptr, cast<llvm::ConstantInt>(Result)};
2189+
}
2190+
21322191
ConstantLValue
21332192
ConstantLValueEmitter::VisitBlockExpr(const BlockExpr *E) {
21342193
StringRef functionName;

clang/lib/CodeGen/CGPointerAuth.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===--- CGPointerAuth.cpp - IR generation for pointer authentication -----===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file contains common routines relating to the emission of
10+
// pointer authentication operations.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "CodeGenModule.h"
15+
#include "clang/CodeGen/CodeGenABITypes.h"
16+
17+
using namespace clang;
18+
using namespace CodeGen;
19+
20+
llvm::Constant *
21+
CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,
22+
llvm::Constant *StorageAddress,
23+
llvm::ConstantInt *OtherDiscriminator) {
24+
llvm::Constant *AddressDiscriminator;
25+
if (StorageAddress) {
26+
assert(StorageAddress->getType() == UnqualPtrTy);
27+
AddressDiscriminator = StorageAddress;
28+
} else {
29+
AddressDiscriminator = llvm::Constant::getNullValue(UnqualPtrTy);
30+
}
31+
32+
llvm::ConstantInt *IntegerDiscriminator;
33+
if (OtherDiscriminator) {
34+
assert(OtherDiscriminator->getType() == Int64Ty);
35+
IntegerDiscriminator = OtherDiscriminator;
36+
} else {
37+
IntegerDiscriminator = llvm::ConstantInt::get(Int64Ty, 0);
38+
}
39+
40+
return llvm::ConstantPtrAuth::get(Pointer,
41+
llvm::ConstantInt::get(Int32Ty, Key),
42+
IntegerDiscriminator, AddressDiscriminator);
43+
}

clang/lib/CodeGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ add_clang_library(clangCodeGen
8989
CGOpenCLRuntime.cpp
9090
CGOpenMPRuntime.cpp
9191
CGOpenMPRuntimeGPU.cpp
92+
CGPointerAuth.cpp
9293
CGRecordLayoutBuilder.cpp
9394
CGStmt.cpp
9495
CGStmtOpenMP.cpp

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,11 @@ class CodeGenModule : public CodeGenTypeCache {
937937
// Return the function body address of the given function.
938938
llvm::Constant *GetFunctionStart(const ValueDecl *Decl);
939939

940+
llvm::Constant *
941+
getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,
942+
llvm::Constant *StorageAddress,
943+
llvm::ConstantInt *OtherDiscriminator);
944+
940945
// Return whether RTTI information should be emitted for this target.
941946
bool shouldEmitRTTI(bool ForEH = false) {
942947
return (ForEH || getLangOpts().RTTI) && !getLangOpts().CUDAIsDevice &&

clang/lib/Headers/ptrauth.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,30 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
6868
On arm64e, the integer must fall within the range of a uint16_t;
6969
other bits may be ignored.
7070
71+
For the purposes of ptrauth_sign_constant, the result of calling
72+
this function is considered a constant expression if the arguments
73+
are constant. Some restrictions may be imposed on the pointer.
74+
7175
The first argument must be an expression of pointer type.
7276
The second argument must be an expression of integer type.
7377
The result will have type uintptr_t. */
7478
#define ptrauth_blend_discriminator(__pointer, __integer) \
7579
__builtin_ptrauth_blend_discriminator(__pointer, __integer)
7680

81+
/* Return a signed pointer for a constant address in a manner which guarantees
82+
a non-attackable sequence.
83+
84+
The value must be a constant expression of pointer type which evaluates to
85+
a non-null pointer.
86+
The key must be a constant expression of type ptrauth_key.
87+
The extra data must be a constant expression of pointer or integer type;
88+
if an integer, it will be coerced to ptrauth_extra_data_t.
89+
The result will have the same type as the original value.
90+
91+
This can be used in constant expressions. */
92+
#define ptrauth_sign_constant(__value, __key, __data) \
93+
__builtin_ptrauth_sign_constant(__value, __key, __data)
94+
7795
/* Add a signature to the given pointer value using a specific key,
7896
using the given extra data as a salt to the signing process.
7997
@@ -175,6 +193,13 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
175193
((ptrauth_extra_data_t)0); \
176194
})
177195

196+
#define ptrauth_sign_constant(__value, __key, __data) \
197+
({ \
198+
(void)__key; \
199+
(void)__data; \
200+
__value; \
201+
})
202+
178203
#define ptrauth_sign_unauthenticated(__value, __key, __data) \
179204
({ \
180205
(void)__key; \

0 commit comments

Comments
 (0)