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

Conversation

ahmedbougacha
Copy link
Member

This exposes the ABI-stable hash function that allows computing a 16-bit discriminator from a constant string.

This allows manually matching the implicit string discriminators computed in the ABI (e.g., from mangled names for vtable pointer/entry signing), as well as enabling the use of interesting discriminators when manually annotating specific pointers with the __ptrauth qualifier.

@llvmbot llvmbot added clang Clang issues not falling into any other category backend:X86 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics labels May 31, 2024
@llvmbot
Copy link
Member

llvmbot commented May 31, 2024

@llvm/pr-subscribers-backend-aarch64
@llvm/pr-subscribers-backend-x86

@llvm/pr-subscribers-clang

Author: Ahmed Bougacha (ahmedbougacha)

Changes

This exposes the ABI-stable hash function that allows computing a 16-bit discriminator from a constant string.

This allows manually matching the implicit string discriminators computed in the ABI (e.g., from mangled names for vtable pointer/entry signing), as well as enabling the use of interesting discriminators when manually annotating specific pointers with the __ptrauth qualifier.


Full diff: https://github.com/llvm/llvm-project/pull/93903.diff

7 Files Affected:

  • (modified) clang/include/clang/Basic/Builtins.td (+6)
  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2)
  • (modified) clang/lib/AST/ExprConstant.cpp (+7)
  • (modified) clang/lib/Headers/ptrauth.h (+17)
  • (modified) clang/lib/Sema/SemaChecking.cpp (+20)
  • (modified) clang/test/CodeGen/ptrauth-intrinsics.c (+13)
  • (modified) clang/test/Sema/ptrauth-intrinsics-macro.c (+5)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 11982af3fa609..836697632a3bc 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -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 {
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f15cba63624ea..64add46248c69 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -928,6 +928,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++.
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f1aa19e4409e1..eafecfb5fe5b1 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -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>
@@ -12583,6 +12584,12 @@ 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: {
+    auto literal = cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts());
+    auto result = getPointerAuthStableSipHash16(literal->getString());
+    return Success(result, E);
+  }
+
   case Builtin::BI__builtin_ffs:
   case Builtin::BI__builtin_ffsl:
   case Builtin::BI__builtin_ffsll: {
diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h
index 036665d75a91b..3e58af1802084 100644
--- a/clang/lib/Headers/ptrauth.h
+++ b/clang/lib/Headers/ptrauth.h
@@ -135,6 +135,17 @@ 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 result can be used as the second argument to
+   ptrauth_blend_discriminator or the third argument to the
+   __ptrauth qualifier.  It has type size_t.
+
+   The argument must be a string literal.
+   A call to this function is an integer constant expression. */
+#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.
 
@@ -196,6 +207,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;                                                             \
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index c3251f3cc9d81..f6012ef4b3601 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2156,6 +2156,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.
+  Expr *arg = call->getArgs()[0]->IgnoreParenImpCasts();
+
+  // Operand must be an ordinary or UTF-8 string literal.
+  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();
@@ -2922,6 +2940,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:
diff --git a/clang/test/CodeGen/ptrauth-intrinsics.c b/clang/test/CodeGen/ptrauth-intrinsics.c
index 17f28dddb3801..d602325da8b17 100644
--- a/clang/test/CodeGen/ptrauth-intrinsics.c
+++ b/clang/test/CodeGen/ptrauth-intrinsics.c
@@ -71,3 +71,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");
+}
diff --git a/clang/test/Sema/ptrauth-intrinsics-macro.c b/clang/test/Sema/ptrauth-intrinsics-macro.c
index 07d6374045145..540f2846b7ce1 100644
--- a/clang/test/Sema/ptrauth-intrinsics-macro.c
+++ b/clang/test/Sema/ptrauth-intrinsics-macro.c
@@ -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;
+}

@ahmedbougacha ahmedbougacha self-assigned this May 31, 2024
@asl asl requested review from kbeyls and smithp35 June 3, 2024 18:51
Copy link
Collaborator

@asl asl left a comment

Choose a reason for hiding this comment

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

See mostly code style nits above

Copy link
Contributor

@kovdan01 kovdan01 left a comment

Choose a reason for hiding this comment

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

The changes themself in terms of functionality look OK to me - but I want someone else with deeper understanding of the context to take a look before this gets merged.

Copy link
Contributor

@kovdan01 kovdan01 left a comment

Choose a reason for hiding this comment

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

LGTM, but I want someone else with deeper understanding of the context to take a look before this gets merged.

@kovdan01 kovdan01 dismissed their stale review June 4, 2024 10:51

Dismiss "changes requested" status

@ahmedbougacha ahmedbougacha force-pushed the users/ahmedbougacha/ptrauth-siphash branch from 8e9ab9c to bf413d6 Compare June 4, 2024 22:13
Copy link
Contributor

@kovdan01 kovdan01 left a comment

Choose a reason for hiding this comment

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

@ahmedbougacha After the latest force-push, the PR seems to contain SipHash-related changes from PRs 93902, 94393 and 94394. Could you please limit the changes only to those which are actually being intended to be merged as a part of this PR and resolve merge conflicts with the base branch?

I'd like to take one more look at this since there were updates since my latest feedback, but with different changes mixed, it's a bit messy.

@ahmedbougacha ahmedbougacha force-pushed the users/ahmedbougacha/ptrauth-siphash branch from bb44624 to b0a19c3 Compare June 15, 2024 00:14
Base automatically changed from users/ahmedbougacha/ptrauth-siphash to main June 15, 2024 00:57
@asl
Copy link
Collaborator

asl commented Jun 15, 2024

@ahmedbougacha Will you please rebase?

This exposes the ABI-stable hash function that allows computing a 16-bit
discriminator from a constant string.

This allows manually matching the implicit string discriminators
computed in the ABI (e.g., from mangled names for vtable pointer/entry
signing), as well as enabling the use of interesting discriminators when
manually annotating specific pointers with the __ptrauth qualifier.

Co-Authored-By: John McCall <[email protected]>
- add missing sema test
- also test ELF codegen for intrinsics
- various capitalization and type nits
- tweaks to header/doc comments
- add test for wide string literal
@ahmedbougacha ahmedbougacha force-pushed the users/ahmedbougacha/ptrauth-string-discriminator branch from 8e7d4bc to 11e7dcc Compare June 18, 2024 20:55
Copy link
Collaborator

@asl asl left a comment

Choose a reason for hiding this comment

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

Thanks!

@ahmedbougacha ahmedbougacha merged commit 50b9193 into main Jun 20, 2024
8 checks passed
@ahmedbougacha ahmedbougacha deleted the users/ahmedbougacha/ptrauth-string-discriminator branch June 20, 2024 18:55
AlexisPerry pushed a commit to llvm-project-tlp/llvm-project that referenced this pull request Jul 9, 2024
This exposes the ABI-stable hash function that allows computing a 16-bit
discriminator from a constant string.

This allows manually matching the implicit string discriminators
computed in the ABI (e.g., from mangled names for vtable pointer/entry
signing), as well as enabling the use of interesting discriminators when
manually annotating specific pointers with the __ptrauth qualifier.

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.

Co-authored-by: John McCall <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:AArch64 backend:X86 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics clang Clang issues not falling into any other category
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

4 participants