https://github.com/asl created https://github.com/llvm/llvm-project/pull/140276

compared to other integer types when computing function pointer type 
discriminator.

These parameter types have different parameter passing ABI as compared to 
ordinary integer types (e.g. require 2 registers instead of 1) and therefore 
this parameter passing difference could potentially be exploited should 
function pointer is substituted.

>From 26e6ea21540d03c6aee6281059cd3b8e3e4b3ee7 Mon Sep 17 00:00:00 2001
From: Anton Korobeynikov <an...@korobeynikov.info>
Date: Fri, 16 May 2025 19:25:57 +0300
Subject: [PATCH] [PAuth] Use different discriminators for __int128_t /
 __uint128_t / _BitInt(n) compared to other integer types when computing
 function pointer type discriminator.

These parameter types have different parameter passing ABI as compared to
ordinary integer types (e.g. require 2 registers instead of 1) and therefore
this parameter passing difference could potentially be exploited should function
pointer is substituted.
---
 clang/lib/AST/ASTContext.cpp                  | 14 ++++++---
 .../ptrauth-function-type-discriminator.c     | 31 +++++++++++++++++++
 2 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index c58cd2c93fb60..bbaaff6bcda4e 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3383,21 +3383,27 @@ static void encodeTypeForFunctionPointerAuth(const 
ASTContext &Ctx,
 
   // Don't bother discriminating based on these types.
   case Type::Pipe:
-  case Type::BitInt:
   case Type::ConstantMatrix:
     OS << "?";
     return;
 
+  case Type::BitInt: {
+    const auto *BtTy = T->castAs<BitIntType>();
+    OS << "D" << (BtTy->isUnsigned() ? "U" : "B") << BtTy->getNumBits() << "_";
+    return;
+  }
+
   case Type::Builtin: {
     const auto *BTy = T->castAs<BuiltinType>();
-    switch (BTy->getKind()) {
+    const auto Kind = BTy->getKind();
+    switch (Kind) {
 #define SIGNED_TYPE(Id, SingletonId)                                           
\
   case BuiltinType::Id:                                                        
\
-    OS << "i";                                                                 
\
+    OS << (Kind == BuiltinType::Int128 ? "n" : "i");                           
\
     return;
 #define UNSIGNED_TYPE(Id, SingletonId)                                         
\
   case BuiltinType::Id:                                                        
\
-    OS << "i";                                                                 
\
+    OS << (Kind == BuiltinType::UInt128 ? "o" : "i");                          
\
     return;
 #define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
 #define BUILTIN_TYPE(Id, SingletonId)
diff --git a/clang/test/CodeGen/ptrauth-function-type-discriminator.c 
b/clang/test/CodeGen/ptrauth-function-type-discriminator.c
index 0952c1abf6c07..9bf4a8874c3c3 100644
--- a/clang/test/CodeGen/ptrauth-function-type-discriminator.c
+++ b/clang/test/CodeGen/ptrauth-function-type-discriminator.c
@@ -65,6 +65,37 @@ void (*fptr3)(void) = 
__builtin_ptrauth_sign_constant(&external_function, 2, 26)
 // CHECK: @fptr4 = global ptr ptrauth (ptr @external_function, i32 2, i64 26, 
ptr @fptr4)
 void (*fptr4)(void) = __builtin_ptrauth_sign_constant(&external_function, 2, 
__builtin_ptrauth_blend_discriminator(&fptr4, 26));
 
+extern void external_function_int(int);
+extern void external_function_char(char);
+extern void external_function_i128(__int128_t);
+extern void external_function_u128(__uint128_t);
+extern void external_function_b128(_BitInt(128));
+extern void external_function_b8(_BitInt(8));
+
+// Check discriminators of functions taking integer type arguments:
+
+//  - Builtin integer types should be discriminated equally (so, pointer to
+//  function taking int argument should accept function taking char argument
+//  - _BitInt types are guaranteed distinct and therefore should be 
discriminated
+//  differently
+//  - __int128_t / __uint128_t are passed differently than char / int / long
+//  (require two registers instead of one) and therefore should be 
discriminated
+//  differently.
+
+// CHECK: @fptr5 = global ptr ptrauth (ptr @external_function_int, i32 0, i64 
2712)
+// CHECK: @fptr6 = global ptr ptrauth (ptr @external_function_char, i32 0, i64 
2712)
+void (*fptr5)(int) = external_function_int;
+void (*fptr6)(char) = external_function_char;
+
+// CHECK: @fptr7 = global ptr ptrauth (ptr @external_function_i128, i32 0, i64 
23141)
+// CHECK: @fptr8 = global ptr ptrauth (ptr @external_function_u128, i32 0, i64 
45743)
+// CHECK: @fptr9 = global ptr ptrauth (ptr @external_function_b128, i32 0, i64 
17854)
+// CHECK: @fptr10 = global ptr ptrauth (ptr @external_function_b8, i32 0, i64 
26383)
+void (*fptr7)(__int128_t) = external_function_i128;
+void (*fptr8)(__uint128_t) = external_function_u128;
+void (*fptr9)(_BitInt(128)) = external_function_b128;
+void (*fptr10)(_BitInt(8)) = external_function_b8;
+
 // CHECK-LABEL: define{{.*}} void @test_call()
 void test_call() {
   // CHECK:      [[T0:%.*]] = load ptr, ptr @fnptr,

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to