Skip to content

[clang] Define ptrauth_sign_constant builtin. #93904

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions clang/docs/PointerAuthentication.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to have this term described more deeply. Do you mean an absence of a signing oracle when talking about a non-attackable sequence?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Later additions to this document describe that in depth, you can look for

[clang][docs] Document the ptrauth security model.

on my branch

Copy link
Contributor

@kovdan01 kovdan01 Jun 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, now I see that. I suppose we can leave the docs "as is" for this PR and submit missing parts as separate PRs later.


``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``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
59 changes: 59 additions & 0 deletions clang/lib/CodeGen/CGExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1924,6 +1924,12 @@ class ConstantLValueEmitter : public ConstStmtVisitor<ConstantLValueEmitter,
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();
}
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
43 changes: 43 additions & 0 deletions clang/lib/CodeGen/CGPointerAuth.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ add_clang_library(clangCodeGen
CGOpenCLRuntime.cpp
CGOpenMPRuntime.cpp
CGOpenMPRuntimeGPU.cpp
CGPointerAuth.cpp
CGRecordLayoutBuilder.cpp
CGStmt.cpp
CGStmtOpenMP.cpp
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,11 @@ class CodeGenModule : public CodeGenTypeCache {
// 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 &&
Expand Down
25 changes: 25 additions & 0 deletions clang/lib/Headers/ptrauth.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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; \
Expand Down
Loading
Loading