[clang] Define ptrauth_sign_constant builtin. (#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 <rjmccall@apple.com>
This commit is contained in:
parent
50b9193781
commit
7c814c13d0
@ -356,6 +356,25 @@ Given that ``signedPointer`` matches the layout for signed pointers signed with
|
||||
the given key, extract the raw pointer from it. This operation does not trap
|
||||
and cannot fail, even if the pointer is not validly signed.
|
||||
|
||||
``ptrauth_sign_constant``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
ptrauth_sign_constant(pointer, key, discriminator)
|
||||
|
||||
Return a signed pointer for a constant address in a manner which guarantees
|
||||
a non-attackable sequence.
|
||||
|
||||
``pointer`` must be a constant expression of pointer type which evaluates to
|
||||
a non-null pointer.
|
||||
``key`` must be a constant expression of type ``ptrauth_key``.
|
||||
``discriminator`` 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 ``pointer``.
|
||||
|
||||
This can be used in constant expressions.
|
||||
|
||||
``ptrauth_sign_unauthenticated``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@ -4393,6 +4393,12 @@ def PtrauthSignUnauthenticated : Builtin {
|
||||
let Prototype = "void*(void*,int,void*)";
|
||||
}
|
||||
|
||||
def PtrauthSignConstant : Builtin {
|
||||
let Spellings = ["__builtin_ptrauth_sign_constant"];
|
||||
let Attributes = [CustomTypeChecking, NoThrow, Const, Constexpr];
|
||||
let Prototype = "void*(void*,int,void*)";
|
||||
}
|
||||
|
||||
def PtrauthSignGenericData : Builtin {
|
||||
let Spellings = ["__builtin_ptrauth_sign_generic_data"];
|
||||
let Attributes = [CustomTypeChecking, NoThrow, Const];
|
||||
|
||||
@ -924,6 +924,13 @@ def err_ptrauth_value_bad_type :
|
||||
Error<"%select{signed value|extra discriminator|blended pointer|blended "
|
||||
"integer}0 must have %select{pointer|integer|pointer or integer}1 "
|
||||
"type; type here is %2">;
|
||||
def err_ptrauth_bad_constant_pointer :
|
||||
Error<"argument to ptrauth_sign_constant must refer to a global variable "
|
||||
"or function">;
|
||||
def err_ptrauth_bad_constant_discriminator :
|
||||
Error<"discriminator argument to ptrauth_sign_constant must be a constant "
|
||||
"integer, the address of the global variable where the result "
|
||||
"will be stored, or a blend of the two">;
|
||||
def warn_ptrauth_sign_null_pointer :
|
||||
Warning<"signing a null pointer will yield a non-null pointer">,
|
||||
InGroup<PtrAuthNullPointers>;
|
||||
|
||||
@ -2042,6 +2042,7 @@ static bool IsNoOpCall(const CallExpr *E) {
|
||||
unsigned Builtin = E->getBuiltinCallee();
|
||||
return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
|
||||
Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
|
||||
Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
|
||||
Builtin == Builtin::BI__builtin_function_start);
|
||||
}
|
||||
|
||||
|
||||
@ -5293,6 +5293,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
|
||||
case Builtin::BI__iso_volatile_store64:
|
||||
return RValue::get(EmitISOVolatileStore(*this, E));
|
||||
|
||||
case Builtin::BI__builtin_ptrauth_sign_constant:
|
||||
return RValue::get(ConstantEmitter(*this).emitAbstract(E, E->getType()));
|
||||
|
||||
case Builtin::BI__builtin_ptrauth_auth:
|
||||
case Builtin::BI__builtin_ptrauth_auth_and_resign:
|
||||
case Builtin::BI__builtin_ptrauth_blend_discriminator:
|
||||
|
||||
@ -1924,6 +1924,12 @@ private:
|
||||
ConstantLValue VisitMaterializeTemporaryExpr(
|
||||
const MaterializeTemporaryExpr *E);
|
||||
|
||||
ConstantLValue emitPointerAuthSignConstant(const CallExpr *E);
|
||||
llvm::Constant *emitPointerAuthPointer(const Expr *E);
|
||||
unsigned emitPointerAuthKey(const Expr *E);
|
||||
std::pair<llvm::Constant *, llvm::ConstantInt *>
|
||||
emitPointerAuthDiscriminator(const Expr *E);
|
||||
|
||||
bool hasNonZeroOffset() const {
|
||||
return !Value.getLValueOffset().isZero();
|
||||
}
|
||||
@ -2116,6 +2122,10 @@ ConstantLValueEmitter::VisitCallExpr(const CallExpr *E) {
|
||||
if (builtin == Builtin::BI__builtin_function_start)
|
||||
return CGM.GetFunctionStart(
|
||||
E->getArg(0)->getAsBuiltinConstantDeclRef(CGM.getContext()));
|
||||
|
||||
if (builtin == Builtin::BI__builtin_ptrauth_sign_constant)
|
||||
return emitPointerAuthSignConstant(E);
|
||||
|
||||
if (builtin != Builtin::BI__builtin___CFStringMakeConstantString &&
|
||||
builtin != Builtin::BI__builtin___NSStringMakeConstantString)
|
||||
return nullptr;
|
||||
@ -2129,6 +2139,55 @@ ConstantLValueEmitter::VisitCallExpr(const CallExpr *E) {
|
||||
}
|
||||
}
|
||||
|
||||
ConstantLValue
|
||||
ConstantLValueEmitter::emitPointerAuthSignConstant(const CallExpr *E) {
|
||||
llvm::Constant *UnsignedPointer = emitPointerAuthPointer(E->getArg(0));
|
||||
unsigned Key = emitPointerAuthKey(E->getArg(1));
|
||||
auto [StorageAddress, OtherDiscriminator] =
|
||||
emitPointerAuthDiscriminator(E->getArg(2));
|
||||
|
||||
llvm::Constant *SignedPointer = CGM.getConstantSignedPointer(
|
||||
UnsignedPointer, Key, StorageAddress, OtherDiscriminator);
|
||||
return SignedPointer;
|
||||
}
|
||||
|
||||
llvm::Constant *ConstantLValueEmitter::emitPointerAuthPointer(const Expr *E) {
|
||||
Expr::EvalResult Result;
|
||||
bool Succeeded = E->EvaluateAsRValue(Result, CGM.getContext());
|
||||
assert(Succeeded);
|
||||
(void)Succeeded;
|
||||
|
||||
// The assertions here are all checked by Sema.
|
||||
assert(Result.Val.isLValue());
|
||||
return ConstantEmitter(CGM, Emitter.CGF)
|
||||
.emitAbstract(E->getExprLoc(), Result.Val, E->getType());
|
||||
}
|
||||
|
||||
unsigned ConstantLValueEmitter::emitPointerAuthKey(const Expr *E) {
|
||||
return E->EvaluateKnownConstInt(CGM.getContext()).getZExtValue();
|
||||
}
|
||||
|
||||
std::pair<llvm::Constant *, llvm::ConstantInt *>
|
||||
ConstantLValueEmitter::emitPointerAuthDiscriminator(const Expr *E) {
|
||||
E = E->IgnoreParens();
|
||||
|
||||
if (const auto *Call = dyn_cast<CallExpr>(E)) {
|
||||
if (Call->getBuiltinCallee() ==
|
||||
Builtin::BI__builtin_ptrauth_blend_discriminator) {
|
||||
llvm::Constant *Pointer = ConstantEmitter(CGM).emitAbstract(
|
||||
Call->getArg(0), Call->getArg(0)->getType());
|
||||
auto *Extra = cast<llvm::ConstantInt>(ConstantEmitter(CGM).emitAbstract(
|
||||
Call->getArg(1), Call->getArg(1)->getType()));
|
||||
return {Pointer, Extra};
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Constant *Result = ConstantEmitter(CGM).emitAbstract(E, E->getType());
|
||||
if (Result->getType()->isPointerTy())
|
||||
return {Result, nullptr};
|
||||
return {nullptr, cast<llvm::ConstantInt>(Result)};
|
||||
}
|
||||
|
||||
ConstantLValue
|
||||
ConstantLValueEmitter::VisitBlockExpr(const BlockExpr *E) {
|
||||
StringRef functionName;
|
||||
|
||||
43
clang/lib/CodeGen/CGPointerAuth.cpp
Normal file
43
clang/lib/CodeGen/CGPointerAuth.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
//===--- CGPointerAuth.cpp - IR generation for pointer authentication -----===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains common routines relating to the emission of
|
||||
// pointer authentication operations.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CodeGenModule.h"
|
||||
#include "clang/CodeGen/CodeGenABITypes.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
llvm::Constant *
|
||||
CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,
|
||||
llvm::Constant *StorageAddress,
|
||||
llvm::ConstantInt *OtherDiscriminator) {
|
||||
llvm::Constant *AddressDiscriminator;
|
||||
if (StorageAddress) {
|
||||
assert(StorageAddress->getType() == UnqualPtrTy);
|
||||
AddressDiscriminator = StorageAddress;
|
||||
} else {
|
||||
AddressDiscriminator = llvm::Constant::getNullValue(UnqualPtrTy);
|
||||
}
|
||||
|
||||
llvm::ConstantInt *IntegerDiscriminator;
|
||||
if (OtherDiscriminator) {
|
||||
assert(OtherDiscriminator->getType() == Int64Ty);
|
||||
IntegerDiscriminator = OtherDiscriminator;
|
||||
} else {
|
||||
IntegerDiscriminator = llvm::ConstantInt::get(Int64Ty, 0);
|
||||
}
|
||||
|
||||
return llvm::ConstantPtrAuth::get(Pointer,
|
||||
llvm::ConstantInt::get(Int32Ty, Key),
|
||||
IntegerDiscriminator, AddressDiscriminator);
|
||||
}
|
||||
@ -89,6 +89,7 @@ add_clang_library(clangCodeGen
|
||||
CGOpenCLRuntime.cpp
|
||||
CGOpenMPRuntime.cpp
|
||||
CGOpenMPRuntimeGPU.cpp
|
||||
CGPointerAuth.cpp
|
||||
CGRecordLayoutBuilder.cpp
|
||||
CGStmt.cpp
|
||||
CGStmtOpenMP.cpp
|
||||
|
||||
@ -937,6 +937,11 @@ public:
|
||||
// Return the function body address of the given function.
|
||||
llvm::Constant *GetFunctionStart(const ValueDecl *Decl);
|
||||
|
||||
llvm::Constant *
|
||||
getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,
|
||||
llvm::Constant *StorageAddress,
|
||||
llvm::ConstantInt *OtherDiscriminator);
|
||||
|
||||
// Return whether RTTI information should be emitted for this target.
|
||||
bool shouldEmitRTTI(bool ForEH = false) {
|
||||
return (ForEH || getLangOpts().RTTI) && !getLangOpts().CUDAIsDevice &&
|
||||
|
||||
@ -68,12 +68,30 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
|
||||
On arm64e, the integer must fall within the range of a uint16_t;
|
||||
other bits may be ignored.
|
||||
|
||||
For the purposes of ptrauth_sign_constant, the result of calling
|
||||
this function is considered a constant expression if the arguments
|
||||
are constant. Some restrictions may be imposed on the pointer.
|
||||
|
||||
The first argument must be an expression of pointer type.
|
||||
The second argument must be an expression of integer type.
|
||||
The result will have type uintptr_t. */
|
||||
#define ptrauth_blend_discriminator(__pointer, __integer) \
|
||||
__builtin_ptrauth_blend_discriminator(__pointer, __integer)
|
||||
|
||||
/* Return a signed pointer for a constant address in a manner which guarantees
|
||||
a non-attackable sequence.
|
||||
|
||||
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. */
|
||||
#define ptrauth_sign_constant(__value, __key, __data) \
|
||||
__builtin_ptrauth_sign_constant(__value, __key, __data)
|
||||
|
||||
/* Add a signature to the given pointer value using a specific key,
|
||||
using the given extra data as a salt to the signing process.
|
||||
|
||||
@ -175,6 +193,13 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
|
||||
((ptrauth_extra_data_t)0); \
|
||||
})
|
||||
|
||||
#define ptrauth_sign_constant(__value, __key, __data) \
|
||||
({ \
|
||||
(void)__key; \
|
||||
(void)__data; \
|
||||
__value; \
|
||||
})
|
||||
|
||||
#define ptrauth_sign_unauthenticated(__value, __key, __data) \
|
||||
({ \
|
||||
(void)__key; \
|
||||
|
||||
@ -2040,8 +2040,23 @@ bool Sema::checkConstantPointerAuthKey(Expr *Arg, unsigned &Result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool checkPointerAuthValue(Sema &S, Expr *&Arg,
|
||||
PointerAuthOpKind OpKind) {
|
||||
static std::pair<const ValueDecl *, CharUnits>
|
||||
findConstantBaseAndOffset(Sema &S, Expr *E) {
|
||||
// Must evaluate as a pointer.
|
||||
Expr::EvalResult Result;
|
||||
if (!E->EvaluateAsRValue(Result, S.Context) || !Result.Val.isLValue())
|
||||
return {nullptr, CharUnits()};
|
||||
|
||||
const auto *BaseDecl =
|
||||
Result.Val.getLValueBase().dyn_cast<const ValueDecl *>();
|
||||
if (!BaseDecl)
|
||||
return {nullptr, CharUnits()};
|
||||
|
||||
return {BaseDecl, Result.Val.getLValueOffset()};
|
||||
}
|
||||
|
||||
static bool checkPointerAuthValue(Sema &S, Expr *&Arg, PointerAuthOpKind OpKind,
|
||||
bool RequireConstant = false) {
|
||||
if (Arg->hasPlaceholderType()) {
|
||||
ExprResult R = S.CheckPlaceholderExpr(Arg);
|
||||
if (R.isInvalid())
|
||||
@ -2084,16 +2099,87 @@ static bool checkPointerAuthValue(Sema &S, Expr *&Arg,
|
||||
if (convertArgumentToType(S, Arg, ExpectedTy))
|
||||
return true;
|
||||
|
||||
// Warn about null pointers for non-generic sign and auth operations.
|
||||
if ((OpKind == PAO_Sign || OpKind == PAO_Auth) &&
|
||||
Arg->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) {
|
||||
S.Diag(Arg->getExprLoc(), OpKind == PAO_Sign
|
||||
? diag::warn_ptrauth_sign_null_pointer
|
||||
: diag::warn_ptrauth_auth_null_pointer)
|
||||
<< Arg->getSourceRange();
|
||||
if (!RequireConstant) {
|
||||
// Warn about null pointers for non-generic sign and auth operations.
|
||||
if ((OpKind == PAO_Sign || OpKind == PAO_Auth) &&
|
||||
Arg->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) {
|
||||
S.Diag(Arg->getExprLoc(), OpKind == PAO_Sign
|
||||
? diag::warn_ptrauth_sign_null_pointer
|
||||
: diag::warn_ptrauth_auth_null_pointer)
|
||||
<< Arg->getSourceRange();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
// Perform special checking on the arguments to ptrauth_sign_constant.
|
||||
|
||||
// The main argument.
|
||||
if (OpKind == PAO_Sign) {
|
||||
// Require the value we're signing to have a special form.
|
||||
auto [BaseDecl, Offset] = findConstantBaseAndOffset(S, Arg);
|
||||
bool Invalid;
|
||||
|
||||
// Must be rooted in a declaration reference.
|
||||
if (!BaseDecl)
|
||||
Invalid = true;
|
||||
|
||||
// If it's a function declaration, we can't have an offset.
|
||||
else if (isa<FunctionDecl>(BaseDecl))
|
||||
Invalid = !Offset.isZero();
|
||||
|
||||
// Otherwise we're fine.
|
||||
else
|
||||
Invalid = false;
|
||||
|
||||
if (Invalid)
|
||||
S.Diag(Arg->getExprLoc(), diag::err_ptrauth_bad_constant_pointer);
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
// The discriminator argument.
|
||||
assert(OpKind == PAO_Discriminator);
|
||||
|
||||
// Must be a pointer or integer or blend thereof.
|
||||
Expr *Pointer = nullptr;
|
||||
Expr *Integer = nullptr;
|
||||
if (auto *Call = dyn_cast<CallExpr>(Arg->IgnoreParens())) {
|
||||
if (Call->getBuiltinCallee() ==
|
||||
Builtin::BI__builtin_ptrauth_blend_discriminator) {
|
||||
Pointer = Call->getArg(0);
|
||||
Integer = Call->getArg(1);
|
||||
}
|
||||
}
|
||||
if (!Pointer && !Integer) {
|
||||
if (Arg->getType()->isPointerType())
|
||||
Pointer = Arg;
|
||||
else
|
||||
Integer = Arg;
|
||||
}
|
||||
|
||||
// Check the pointer.
|
||||
bool Invalid = false;
|
||||
if (Pointer) {
|
||||
assert(Pointer->getType()->isPointerType());
|
||||
|
||||
// TODO: if we're initializing a global, check that the address is
|
||||
// somehow related to what we're initializing. This probably will
|
||||
// never really be feasible and we'll have to catch it at link-time.
|
||||
auto [BaseDecl, Offset] = findConstantBaseAndOffset(S, Pointer);
|
||||
if (!BaseDecl || !isa<VarDecl>(BaseDecl))
|
||||
Invalid = true;
|
||||
}
|
||||
|
||||
// Check the integer.
|
||||
if (Integer) {
|
||||
assert(Integer->getType()->isIntegerType());
|
||||
if (!Integer->isEvaluatable(S.Context))
|
||||
Invalid = true;
|
||||
}
|
||||
|
||||
if (Invalid)
|
||||
S.Diag(Arg->getExprLoc(), diag::err_ptrauth_bad_constant_discriminator);
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
static ExprResult PointerAuthStrip(Sema &S, CallExpr *Call) {
|
||||
@ -2136,14 +2222,16 @@ static ExprResult PointerAuthSignGenericData(Sema &S, CallExpr *Call) {
|
||||
}
|
||||
|
||||
static ExprResult PointerAuthSignOrAuth(Sema &S, CallExpr *Call,
|
||||
PointerAuthOpKind OpKind) {
|
||||
PointerAuthOpKind OpKind,
|
||||
bool RequireConstant) {
|
||||
if (S.checkArgCount(Call, 3))
|
||||
return ExprError();
|
||||
if (checkPointerAuthEnabled(S, Call))
|
||||
return ExprError();
|
||||
if (checkPointerAuthValue(S, Call->getArgs()[0], OpKind) ||
|
||||
if (checkPointerAuthValue(S, Call->getArgs()[0], OpKind, RequireConstant) ||
|
||||
checkPointerAuthKey(S, Call->getArgs()[1]) ||
|
||||
checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator))
|
||||
checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator,
|
||||
RequireConstant))
|
||||
return ExprError();
|
||||
|
||||
Call->setType(Call->getArgs()[0]->getType());
|
||||
@ -2943,10 +3031,15 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
|
||||
return PointerAuthStrip(*this, TheCall);
|
||||
case Builtin::BI__builtin_ptrauth_blend_discriminator:
|
||||
return PointerAuthBlendDiscriminator(*this, TheCall);
|
||||
case Builtin::BI__builtin_ptrauth_sign_constant:
|
||||
return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign,
|
||||
/*RequireConstant=*/true);
|
||||
case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
|
||||
return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign);
|
||||
return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign,
|
||||
/*RequireConstant=*/false);
|
||||
case Builtin::BI__builtin_ptrauth_auth:
|
||||
return PointerAuthSignOrAuth(*this, TheCall, PAO_Auth);
|
||||
return PointerAuthSignOrAuth(*this, TheCall, PAO_Auth,
|
||||
/*RequireConstant=*/false);
|
||||
case Builtin::BI__builtin_ptrauth_sign_generic_data:
|
||||
return PointerAuthSignGenericData(*this, TheCall);
|
||||
case Builtin::BI__builtin_ptrauth_auth_and_resign:
|
||||
|
||||
33
clang/test/CodeGen/ptrauth-intrinsic-sign-constant.c
Normal file
33
clang/test/CodeGen/ptrauth-intrinsic-sign-constant.c
Normal file
@ -0,0 +1,33 @@
|
||||
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 -triple aarch64-elf -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s
|
||||
|
||||
extern int external;
|
||||
|
||||
// CHECK: @ptr1 = global ptr ptrauth (ptr @external, i32 0)
|
||||
void *ptr1 = __builtin_ptrauth_sign_constant(&external, 0, 0);
|
||||
|
||||
// CHECK: @ptr2 = global ptr ptrauth (ptr @external, i32 0, i64 1234)
|
||||
void *ptr2 = __builtin_ptrauth_sign_constant(&external, 0, 1234);
|
||||
|
||||
// CHECK: @ptr3 = global ptr ptrauth (ptr @external, i32 2, i64 0, ptr @ptr3)
|
||||
void *ptr3 = __builtin_ptrauth_sign_constant(&external, 2, &ptr3);
|
||||
|
||||
// CHECK: @ptr4 = global ptr ptrauth (ptr @external, i32 2, i64 26, ptr @ptr4)
|
||||
void *ptr4 = __builtin_ptrauth_sign_constant(&external, 2, __builtin_ptrauth_blend_discriminator(&ptr4, 26));
|
||||
|
||||
// CHECK: @ptr5 = global ptr null
|
||||
void *ptr5;
|
||||
|
||||
void test_sign_constant_code() {
|
||||
// CHECK-LABEL: define {{.*}}void @test_sign_constant_code()
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: store ptr ptrauth (ptr @external, i32 0), ptr @ptr1, align 8
|
||||
// CHECK-NEXT: store ptr ptrauth (ptr @external, i32 2, i64 1234), ptr @ptr2, align 8
|
||||
// CHECK-NEXT: store ptr ptrauth (ptr @external, i32 2, i64 0, ptr @ptr3), ptr @ptr3, align 8
|
||||
// CHECK-NEXT: store ptr ptrauth (ptr @external, i32 2, i64 1234, ptr @ptr4), ptr @ptr4, align 8
|
||||
// CHECK-NEXT: ret void
|
||||
ptr1 = __builtin_ptrauth_sign_constant(&external, 0, 0);
|
||||
ptr2 = __builtin_ptrauth_sign_constant(&external, 2, 1234);
|
||||
ptr3 = __builtin_ptrauth_sign_constant(&external, 2, &ptr3);
|
||||
ptr4 = __builtin_ptrauth_sign_constant(&external, 2, __builtin_ptrauth_blend_discriminator(&ptr4, 1234));
|
||||
}
|
||||
@ -37,3 +37,7 @@ void test_string_discriminator(int *dp) {
|
||||
ptrauth_extra_data_t t0 = ptrauth_string_discriminator("string");
|
||||
(void)t0;
|
||||
}
|
||||
|
||||
void test_sign_constant(int *dp) {
|
||||
dp = ptrauth_sign_constant(&dv, VALID_DATA_KEY, 0);
|
||||
}
|
||||
|
||||
@ -136,3 +136,84 @@ void test_sign_generic_data(int *dp) {
|
||||
|
||||
int *mismatch = __builtin_ptrauth_sign_generic_data(dp, 0); // expected-error {{incompatible integer to pointer conversion initializing 'int *' with an expression of type}}
|
||||
}
|
||||
|
||||
|
||||
typedef int (*fp_t)(int);
|
||||
|
||||
static int dv_weakref __attribute__((weakref("dv")));
|
||||
extern int dv_weak __attribute__((weak));
|
||||
|
||||
int *t_cst_sig1 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY); // expected-error {{too few arguments}}
|
||||
int *t_cst_sig2 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, &dv, &dv); // expected-error {{too many arguments}}
|
||||
|
||||
int *t_cst_sig3 = __builtin_ptrauth_sign_constant(mismatched_type, VALID_DATA_KEY, 0); // expected-error {{signed value must have pointer type; type here is 'struct A'}}
|
||||
int *t_cst_sig4 = __builtin_ptrauth_sign_constant(&dv, mismatched_type, 0); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}
|
||||
int *t_cst_sig5 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, mismatched_type); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}}
|
||||
|
||||
float *t_cst_result = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, 0); // expected-warning {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}}
|
||||
|
||||
int *t_cst_valid1 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, 0);
|
||||
int *t_cst_valid2 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(&dv, 0));
|
||||
int *t_cst_valid3 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(&dv + 8, 0));
|
||||
int *t_cst_valid4 = __builtin_ptrauth_sign_constant(&dv_weak, VALID_DATA_KEY, 0);
|
||||
int *t_cst_valid5 = __builtin_ptrauth_sign_constant(&dv_weakref, VALID_DATA_KEY, 0);
|
||||
|
||||
int *t_cst_ptr = __builtin_ptrauth_sign_constant(NULL, VALID_DATA_KEY, &dv); // expected-error {{argument to ptrauth_sign_constant must refer to a global variable or function}}
|
||||
int *t_cst_key = __builtin_ptrauth_sign_constant(&dv, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}
|
||||
int *t_cst_disc1 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, &fv); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
|
||||
int *t_cst_disc2 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(&fv, 0)); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
|
||||
|
||||
fp_t t_cst_f_valid1 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, 0);
|
||||
fp_t t_cst_f_valid2 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, __builtin_ptrauth_blend_discriminator(&dv, 0));
|
||||
fp_t t_cst_f_valid3 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, __builtin_ptrauth_blend_discriminator(&dv + 8, 0));
|
||||
|
||||
fp_t t_cst_f_key = __builtin_ptrauth_sign_constant(&fv, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}
|
||||
fp_t t_cst_f_disc1 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, &fv); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
|
||||
fp_t t_cst_f_disc2 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, __builtin_ptrauth_blend_discriminator(&fv, 0)); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
|
||||
|
||||
int *t_cst_offset = __builtin_ptrauth_sign_constant((int *)((char*)&dv + 16), VALID_DATA_KEY, 0);
|
||||
fp_t t_cst_f_offset = __builtin_ptrauth_sign_constant((int (*)(int))((char*)&fv + 16), VALID_CODE_KEY, 0); // expected-error {{argument to ptrauth_sign_constant must refer to a global variable or function}}
|
||||
|
||||
void test_sign_constant(int *dp, fp_t fp) {
|
||||
int *sig1 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY); // expected-error {{too few arguments}}
|
||||
int *sig2 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, &dv, &dv); // expected-error {{too many arguments}}
|
||||
|
||||
int *sig3 = __builtin_ptrauth_sign_constant(mismatched_type, VALID_DATA_KEY, 0); // expected-error {{signed value must have pointer type; type here is 'struct A'}}
|
||||
int *sig4 = __builtin_ptrauth_sign_constant(&dv, mismatched_type, 0); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}
|
||||
int *sig5 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, mismatched_type); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}}
|
||||
|
||||
float *result = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, 0); // expected-warning {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}}
|
||||
|
||||
int *valid1 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, 0);
|
||||
int *valid2 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(&dv, 0));
|
||||
int *valid3 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(&dv + 8, 0));
|
||||
int *valid4 = __builtin_ptrauth_sign_constant(&dv_weak, VALID_DATA_KEY, 0);
|
||||
int *valid5 = __builtin_ptrauth_sign_constant(&dv_weakref, VALID_DATA_KEY, 0);
|
||||
|
||||
int *ptr = __builtin_ptrauth_sign_constant(NULL, VALID_DATA_KEY, &dv); // expected-error {{argument to ptrauth_sign_constant must refer to a global variable or function}}
|
||||
int *key = __builtin_ptrauth_sign_constant(&dv, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}
|
||||
int *disc1 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, &fv); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
|
||||
int *disc2 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(&fv, 0)); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
|
||||
|
||||
int *ptr2 = __builtin_ptrauth_sign_constant(dp, VALID_DATA_KEY, 0); // expected-error {{argument to ptrauth_sign_constant must refer to a global variable or function}}
|
||||
int *disc3 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, dp); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
|
||||
int *disc4 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(dp, 0)); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
|
||||
int *disc5 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(&dv, *dp)); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
|
||||
|
||||
fp_t f_valid1 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, 0);
|
||||
fp_t f_valid2 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, __builtin_ptrauth_blend_discriminator(&dv, 0));
|
||||
fp_t f_valid3 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, __builtin_ptrauth_blend_discriminator(&dv + 8, 0));
|
||||
|
||||
fp_t f_key = __builtin_ptrauth_sign_constant(&fv, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}
|
||||
fp_t f_disc1 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, &fv); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
|
||||
fp_t f_disc2 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, __builtin_ptrauth_blend_discriminator(&fv, 0)); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
|
||||
|
||||
fp_t f_ptr = __builtin_ptrauth_sign_constant(fp, VALID_CODE_KEY, 0); // expected-error {{argument to ptrauth_sign_constant must refer to a global variable or function}}
|
||||
fp_t f_disc3 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, dp); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
|
||||
|
||||
fp_t f_disc4 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, __builtin_ptrauth_blend_discriminator(dp, 0)); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
|
||||
fp_t f_disc5 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, __builtin_ptrauth_blend_discriminator(&dv, *dp)); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
|
||||
|
||||
int *offset = __builtin_ptrauth_sign_constant((int *)((char*)&dv + 16), VALID_DATA_KEY, 0);
|
||||
fp_t f_offset = __builtin_ptrauth_sign_constant((fp_t)((char*)&fv + 16), VALID_CODE_KEY, 0); // expected-error {{argument to ptrauth_sign_constant must refer to a global variable or function}}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user