Skip to content

[clang] Define ptrauth_string_discriminator builtin. #93903

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
17 changes: 17 additions & 0 deletions clang/docs/PointerAuthentication.rst
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,23 @@ be done in a single instruction with an immediate integer.
``pointer`` must have pointer type, and ``integer`` must have integer type. The
result has type ``ptrauth_extra_data_t``.

``ptrauth_string_discriminator``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code-block:: c

ptrauth_string_discriminator(string)

Compute a constant discriminator from the given string.

``string`` must be a string literal of ``char`` character type. The result has
type ``ptrauth_extra_data_t``.

The result value is never zero and always within range for both the
``__ptrauth`` qualifier and ``ptrauth_blend_discriminator``.

This can be used in constant expressions.

``ptrauth_strip``
^^^^^^^^^^^^^^^^^

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 @@ -4411,6 +4411,12 @@ def PtrauthAuth : Builtin {
let Prototype = "void*(void*,int,void*)";
}

def PtrauthStringDiscriminator : Builtin {
let Spellings = ["__builtin_ptrauth_string_discriminator"];
let Attributes = [NoThrow, Const, Constexpr];
let Prototype = "size_t(char const*)";
}

// OpenCL v2.0 s6.13.16, s9.17.3.5 - Pipe functions.
// We need the generic prototype, since the packet type could be anything.
def ReadPipe : OCLPipeLangBuiltin {
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,8 @@ def warn_ptrauth_sign_null_pointer :
def warn_ptrauth_auth_null_pointer :
Warning<"authenticating a null pointer will almost certainly trap">,
InGroup<PtrAuthNullPointers>;
def err_ptrauth_string_not_literal : Error<
"argument must be a string literal%select{| of char type}0">;

/// main()
// static main() is not an error in C, just in C++.
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/SipHash.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/raw_ostream.h"
#include <cstring>
Expand Down Expand Up @@ -12590,6 +12591,13 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__builtin_expect_with_probability:
return Visit(E->getArg(0));

case Builtin::BI__builtin_ptrauth_string_discriminator: {
const auto *Literal =
cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts());
uint64_t Result = getPointerAuthStableSipHash(Literal->getString());
return Success(Result, E);
}

case Builtin::BI__builtin_ffs:
case Builtin::BI__builtin_ffsl:
case Builtin::BI__builtin_ffsll: {
Expand Down
19 changes: 19 additions & 0 deletions clang/lib/Headers/ptrauth.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,19 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
#define ptrauth_auth_data(__value, __old_key, __old_data) \
__builtin_ptrauth_auth(__value, __old_key, __old_data)

/* Compute a constant discriminator from the given string.

The argument must be a string literal of char character type. The result
has type ptrauth_extra_data_t.

The result value is never zero and always within range for both the
__ptrauth qualifier and ptrauth_blend_discriminator.

This can be used in constant expressions.
*/
#define ptrauth_string_discriminator(__string) \
__builtin_ptrauth_string_discriminator(__string)

/* Compute a signature for the given pair of pointer-sized values.
The order of the arguments is significant.

Expand Down Expand Up @@ -186,6 +199,12 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
__value; \
})

#define ptrauth_string_discriminator(__string) \
({ \
(void)__string; \
((ptrauth_extra_data_t)0); \
})

#define ptrauth_sign_generic_data(__value, __data) \
({ \
(void)__value; \
Expand Down
20 changes: 20 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2166,6 +2166,24 @@ static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) {
return Call;
}

static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *Call) {
if (checkPointerAuthEnabled(S, Call))
return ExprError();

// We've already performed normal call type-checking.
const Expr *Arg = Call->getArg(0)->IgnoreParenImpCasts();

// Operand must be an ordinary or UTF-8 string literal.
const auto *Literal = dyn_cast<StringLiteral>(Arg);
if (!Literal || Literal->getCharByteWidth() != 1) {
S.Diag(Arg->getExprLoc(), diag::err_ptrauth_string_not_literal)
<< (Literal ? 1 : 0) << Arg->getSourceRange();
return ExprError();
}

return Call;
}

static ExprResult BuiltinLaunder(Sema &S, CallExpr *TheCall) {
if (S.checkArgCount(TheCall, 1))
return ExprError();
Expand Down Expand Up @@ -2933,6 +2951,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return PointerAuthSignGenericData(*this, TheCall);
case Builtin::BI__builtin_ptrauth_auth_and_resign:
return PointerAuthAuthAndResign(*this, TheCall);
case Builtin::BI__builtin_ptrauth_string_discriminator:
return PointerAuthStringDiscriminator(*this, TheCall);
// OpenCL v2.0, s6.13.16 - Pipe functions
case Builtin::BIread_pipe:
case Builtin::BIwrite_pipe:
Expand Down
26 changes: 20 additions & 6 deletions clang/test/CodeGen/ptrauth-intrinsics.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// 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

void (*fnptr)(void);
long int_discriminator;
void *ptr_discriminator;
long signature;

// CHECK-LABEL: define void @test_auth()
// CHECK-LABEL: define {{.*}}void @test_auth()
void test_auth() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
Expand All @@ -17,7 +18,7 @@ void test_auth() {
fnptr = __builtin_ptrauth_auth(fnptr, 0, ptr_discriminator);
}

// CHECK-LABEL: define void @test_strip()
// CHECK-LABEL: define {{.*}}void @test_strip()
void test_strip() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[PTR]] to i64
Expand All @@ -27,7 +28,7 @@ void test_strip() {
fnptr = __builtin_ptrauth_strip(fnptr, 0);
}

// CHECK-LABEL: define void @test_sign_unauthenticated()
// CHECK-LABEL: define {{.*}}void @test_sign_unauthenticated()
void test_sign_unauthenticated() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
Expand All @@ -39,7 +40,7 @@ void test_sign_unauthenticated() {
fnptr = __builtin_ptrauth_sign_unauthenticated(fnptr, 0, ptr_discriminator);
}

// CHECK-LABEL: define void @test_auth_and_resign()
// CHECK-LABEL: define {{.*}}void @test_auth_and_resign()
void test_auth_and_resign() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
Expand All @@ -51,7 +52,7 @@ void test_auth_and_resign() {
fnptr = __builtin_ptrauth_auth_and_resign(fnptr, 0, ptr_discriminator, 3, 15);
}

// CHECK-LABEL: define void @test_blend_discriminator()
// CHECK-LABEL: define {{.*}}void @test_blend_discriminator()
void test_blend_discriminator() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC:%.*]] = load i64, ptr @int_discriminator,
Expand All @@ -61,7 +62,7 @@ void test_blend_discriminator() {
int_discriminator = __builtin_ptrauth_blend_discriminator(fnptr, int_discriminator);
}

// CHECK-LABEL: define void @test_sign_generic_data()
// CHECK-LABEL: define {{.*}}void @test_sign_generic_data()
void test_sign_generic_data() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
Expand All @@ -71,3 +72,16 @@ void test_sign_generic_data() {
// CHECK-NEXT: store i64 [[RESULT]], ptr @signature,
signature = __builtin_ptrauth_sign_generic_data(fnptr, ptr_discriminator);
}

// CHECK-LABEL: define {{.*}}void @test_string_discriminator()
void test_string_discriminator() {
// CHECK: [[X:%.*]] = alloca i32

// Check a couple of random discriminators used by Swift.

// CHECK: store i32 58298, ptr [[X]],
int x = __builtin_ptrauth_string_discriminator("InitializeWithCopy");

// CHECK: store i32 9112, ptr [[X]],
x = __builtin_ptrauth_string_discriminator("DestroyArray");
}
5 changes: 5 additions & 0 deletions clang/test/Sema/ptrauth-intrinsics-macro.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,8 @@ void test(int *dp, int value) {
int t2 = ptrauth_sign_generic_data(dp, 0);
(void)t2;
}

void test_string_discriminator(int *dp) {
ptrauth_extra_data_t t0 = ptrauth_string_discriminator("string");
(void)t0;
}
12 changes: 12 additions & 0 deletions clang/test/Sema/ptrauth.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ void test_blend_discriminator(int *dp, int (*fp)(int), int value) {
float *mismatch = __builtin_ptrauth_blend_discriminator(dp, value); // expected-error {{incompatible integer to pointer conversion initializing 'float *' with an expression of type}}
}

void test_string_discriminator(const char *str) {
__builtin_ptrauth_string_discriminator(); // expected-error {{too few arguments}}
__builtin_ptrauth_string_discriminator(str, str); // expected-error {{too many arguments}}
(void) __builtin_ptrauth_string_discriminator("test string"); // no warning

__builtin_ptrauth_string_discriminator(str); // expected-error {{argument must be a string literal}}
__builtin_ptrauth_string_discriminator(L"wide test"); // expected-error {{argument must be a string literal}} expected-warning {{incompatible pointer types passing 'int[10]' to parameter of type 'const char *'}}

void *mismatch = __builtin_ptrauth_string_discriminator("test string"); // expected-error {{incompatible integer to pointer conversion initializing 'void *' with an expression of type 'unsigned long'}}
}


void test_sign_unauthenticated(int *dp, int (*fp)(int)) {
__builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY); // expected-error {{too few arguments}}
__builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY, dp, dp); // expected-error {{too many arguments}}
Expand Down
Loading