[clang] [clang] Ensure pointers passed to runtime support functions are correctly signed (PR #98276)
Oliver Hunt via cfe-commits
cfe-commits at lists.llvm.org
Sun Jul 14 15:20:47 PDT 2024
https://github.com/ojhunt updated https://github.com/llvm/llvm-project/pull/98276
>From 4b92c4af87a1a381dad09b243db4d3ec71d64738 Mon Sep 17 00:00:00 2001
From: John McCall <rjmccall at apple.com>
Date: Wed, 18 Sep 2019 02:21:37 -0400
Subject: [PATCH 1/4] Sign function pointers passed to atexit and __cxa_atexit.
Patch by Akira Hatanaka.
---
clang/lib/CodeGen/CGDeclCXX.cpp | 9 +++++--
clang/lib/CodeGen/CodeGenFunction.h | 2 +-
clang/lib/CodeGen/ItaniumCXXABI.cpp | 10 ++++++-
.../CodeGenCXX/ptrauth-static-destructors.cpp | 26 +++++++++++++++++++
4 files changed, 43 insertions(+), 4 deletions(-)
create mode 100644 clang/test/CodeGenCXX/ptrauth-static-destructors.cpp
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index 05dd7ddb86fa6..36248a9c75188 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -232,7 +232,7 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
/// Create a stub function, suitable for being passed to atexit,
/// which passes the given address to the given destructor function.
-llvm::Function *CodeGenFunction::createAtExitStub(const VarDecl &VD,
+llvm::Constant *CodeGenFunction::createAtExitStub(const VarDecl &VD,
llvm::FunctionCallee dtor,
llvm::Constant *addr) {
// Get the destructor function type, void(*)(void).
@@ -264,7 +264,12 @@ llvm::Function *CodeGenFunction::createAtExitStub(const VarDecl &VD,
CGF.FinishFunction();
- return fn;
+ // Get a proper function pointer.
+ FunctionProtoType::ExtProtoInfo EPI(getContext().getDefaultCallingConvention(
+ /*IsVariadic=*/false, /*IsCXXMethod=*/false));
+ QualType fnType = getContext().getFunctionType(getContext().VoidTy,
+ {getContext().VoidPtrTy}, EPI);
+ return CGM.getFunctionPointer(fn, fnType);
}
/// Create a stub function, suitable for being passed to __pt_atexit_np,
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 13f12b5d878a6..e33267c4787fd 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4862,7 +4862,7 @@ class CodeGenFunction : public CodeGenTypeCache {
void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::GlobalVariable *GV,
bool PerformInit);
- llvm::Function *createAtExitStub(const VarDecl &VD, llvm::FunctionCallee Dtor,
+ llvm::Constant *createAtExitStub(const VarDecl &VD, llvm::FunctionCallee Dtor,
llvm::Constant *Addr);
llvm::Function *createTLSAtExitStub(const VarDecl &VD,
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index e1d056765a866..1924c07c1529d 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -2699,6 +2699,14 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
if (llvm::Function *fn = dyn_cast<llvm::Function>(atexit.getCallee()))
fn->setDoesNotThrow();
+ auto &Context = CGF.CGM.getContext();
+ FunctionProtoType::ExtProtoInfo EPI(Context.getDefaultCallingConvention(
+ /*IsVariadic=*/false, /*IsCXXMethod=*/false));
+ QualType fnType =
+ Context.getFunctionType(Context.VoidTy, {Context.VoidPtrTy}, EPI);
+ llvm::Constant *dtorCallee = cast<llvm::Constant>(dtor.getCallee());
+ dtorCallee = CGF.CGM.getFunctionPointer(dtorCallee, fnType);
+
if (!addr)
// addr is null when we are trying to register a dtor annotated with
// __attribute__((destructor)) in a constructor function. Using null here is
@@ -2706,7 +2714,7 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
// function.
addr = llvm::Constant::getNullValue(CGF.Int8PtrTy);
- llvm::Value *args[] = {dtor.getCallee(), addr, handle};
+ llvm::Value *args[] = {dtorCallee, addr, handle};
CGF.EmitNounwindRuntimeCall(atexit, args);
}
diff --git a/clang/test/CodeGenCXX/ptrauth-static-destructors.cpp b/clang/test/CodeGenCXX/ptrauth-static-destructors.cpp
new file mode 100644
index 0000000000000..6c8d0c560681a
--- /dev/null
+++ b/clang/test/CodeGenCXX/ptrauth-static-destructors.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm -std=c++11 %s -o - \
+// RUN: | FileCheck %s --check-prefix=CXAATEXIT
+
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm -std=c++11 %s -o - \
+// RUN: -fno-use-cxa-atexit \
+// RUN: | FileCheck %s --check-prefix=ATEXIT
+
+class Foo {
+ public:
+ ~Foo() {
+ }
+};
+
+Foo global;
+
+// CXAATEXIT: @_ZN3FooD1Ev.ptrauth = private constant { i8*, i32, i64, i64 } { i8* bitcast (%class.Foo* (%class.Foo*)* @_ZN3FooD1Ev to i8*), i32 0, i64 0, i64 0 }, section "llvm.ptrauth", align 8
+// CXAATEXIT: define internal void @__cxx_global_var_init()
+// CXAATEXIT: call i32 @__cxa_atexit(void (i8*)* bitcast ({ i8*, i32, i64, i64 }* @_ZN3FooD1Ev.ptrauth to void (i8*)*), i8* getelementptr inbounds (%class.Foo, %class.Foo* @global, i32 0, i32 0), i8* @__dso_handle)
+
+
+// ATEXIT: @__dtor_global.ptrauth = private constant { i8*, i32, i64, i64 } { i8* bitcast (void ()* @__dtor_global to i8*), i32 0, i64 0, i64 0 }, section "llvm.ptrauth", align 8
+// ATEXIT: define internal void @__cxx_global_var_init()
+// ATEXIT: %{{.*}} = call i32 @atexit(void ()* bitcast ({ i8*, i32, i64, i64 }* @__dtor_global.ptrauth to void ()*))
+
+// ATEXIT: define internal void @__dtor_global() {{.*}} section "__TEXT,__StaticInit,regular,pure_instructions" {
+// ATEXIT: %{{.*}} = call %class.Foo* @_ZN3FooD1Ev(%class.Foo* @global)
>From b00d0b2f361a5537efaba68fbac7cfa8f682581e Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Tue, 9 Jul 2024 23:22:07 -0700
Subject: [PATCH 2/4] Fix build and tests for upstream
---
clang/lib/CodeGen/CGDeclCXX.cpp | 3 ++-
clang/lib/CodeGen/ItaniumCXXABI.cpp | 3 ++-
clang/test/CodeGenCXX/ptrauth-static-destructors.cpp | 8 +++-----
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index 36248a9c75188..2f56355cff90e 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -338,7 +338,8 @@ void CodeGenFunction::registerGlobalDtorWithLLVM(const VarDecl &VD,
llvm::FunctionCallee Dtor,
llvm::Constant *Addr) {
// Create a function which calls the destructor.
- llvm::Function *dtorStub = createAtExitStub(VD, Dtor, Addr);
+ llvm::Function *dtorStub =
+ cast<llvm::Function>(createAtExitStub(VD, Dtor, Addr));
CGM.AddGlobalDtor(dtorStub);
}
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 1924c07c1529d..21023f60e19de 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -4915,7 +4915,8 @@ void XLCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
}
// Create __dtor function for the var decl.
- llvm::Function *DtorStub = CGF.createAtExitStub(D, Dtor, Addr);
+ llvm::Function *DtorStub =
+ cast<llvm::Function>(CGF.createAtExitStub(D, Dtor, Addr));
// Register above __dtor with atexit().
CGF.registerGlobalDtorWithAtExit(DtorStub);
diff --git a/clang/test/CodeGenCXX/ptrauth-static-destructors.cpp b/clang/test/CodeGenCXX/ptrauth-static-destructors.cpp
index 6c8d0c560681a..cad43dc0746df 100644
--- a/clang/test/CodeGenCXX/ptrauth-static-destructors.cpp
+++ b/clang/test/CodeGenCXX/ptrauth-static-destructors.cpp
@@ -13,14 +13,12 @@ class Foo {
Foo global;
-// CXAATEXIT: @_ZN3FooD1Ev.ptrauth = private constant { i8*, i32, i64, i64 } { i8* bitcast (%class.Foo* (%class.Foo*)* @_ZN3FooD1Ev to i8*), i32 0, i64 0, i64 0 }, section "llvm.ptrauth", align 8
// CXAATEXIT: define internal void @__cxx_global_var_init()
-// CXAATEXIT: call i32 @__cxa_atexit(void (i8*)* bitcast ({ i8*, i32, i64, i64 }* @_ZN3FooD1Ev.ptrauth to void (i8*)*), i8* getelementptr inbounds (%class.Foo, %class.Foo* @global, i32 0, i32 0), i8* @__dso_handle)
+// CXAATEXIT: call i32 @__cxa_atexit(ptr ptrauth (ptr @_ZN3FooD1Ev, i32 0), ptr @global, ptr @__dso_handle)
-// ATEXIT: @__dtor_global.ptrauth = private constant { i8*, i32, i64, i64 } { i8* bitcast (void ()* @__dtor_global to i8*), i32 0, i64 0, i64 0 }, section "llvm.ptrauth", align 8
// ATEXIT: define internal void @__cxx_global_var_init()
-// ATEXIT: %{{.*}} = call i32 @atexit(void ()* bitcast ({ i8*, i32, i64, i64 }* @__dtor_global.ptrauth to void ()*))
+// ATEXIT: %{{.*}} = call i32 @atexit(ptr ptrauth (ptr @__dtor_global, i32 0))
// ATEXIT: define internal void @__dtor_global() {{.*}} section "__TEXT,__StaticInit,regular,pure_instructions" {
-// ATEXIT: %{{.*}} = call %class.Foo* @_ZN3FooD1Ev(%class.Foo* @global)
+// ATEXIT: %{{.*}} = call ptr @_ZN3FooD1Ev(ptr @global)
>From b0d4bda0956e3baf23e3c0bc9db0f14dfb5c7156 Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Mon, 27 Sep 2021 08:00:00 -0700
Subject: [PATCH 3/4] [clang] Sign the dtor passed to __cxa_throw as a
void(*)(void*) fptr.
__cxa_throw is declared to take its destructor as void (*)(void *). We
must match that if function pointers can be authenticated with
a discriminator based on their type.
---
clang/lib/CodeGen/ItaniumCXXABI.cpp | 8 ++++++++
clang/test/CodeGenCXX/ptrauth-throw.cpp | 20 ++++++++++++++++++++
2 files changed, 28 insertions(+)
create mode 100644 clang/test/CodeGenCXX/ptrauth-throw.cpp
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 21023f60e19de..489051e95953e 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -1321,8 +1321,16 @@ void ItaniumCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) {
if (const RecordType *RecordTy = ThrowType->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl());
if (!Record->hasTrivialDestructor()) {
+ // __cxa_throw is declared to take its destructor as void (*)(void *). We
+ // must match that if function pointers can be authenticated with a
+ // discriminator based on their type.
+ ASTContext &Ctx = getContext();
+ QualType DtorTy = Ctx.getFunctionType(Ctx.VoidTy, {Ctx.VoidPtrTy},
+ FunctionProtoType::ExtProtoInfo());
+
CXXDestructorDecl *DtorD = Record->getDestructor();
Dtor = CGM.getAddrOfCXXStructor(GlobalDecl(DtorD, Dtor_Complete));
+ Dtor = CGM.getFunctionPointer(Dtor, DtorTy);
}
}
if (!Dtor) Dtor = llvm::Constant::getNullValue(CGM.Int8PtrTy);
diff --git a/clang/test/CodeGenCXX/ptrauth-throw.cpp b/clang/test/CodeGenCXX/ptrauth-throw.cpp
new file mode 100644
index 0000000000000..0e143433ee5a3
--- /dev/null
+++ b/clang/test/CodeGenCXX/ptrauth-throw.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fcxx-exceptions -emit-llvm %s -o - | FileCheck %s
+
+class Foo {
+ public:
+ ~Foo() {
+ }
+};
+
+// CHECK-LABEL: define void @_Z1fv()
+// CHECK: call void @__cxa_throw(ptr %{{.*}}, ptr @_ZTI3Foo, ptr ptrauth (ptr @_ZN3FooD1Ev, i32 0))
+void f() {
+ throw Foo();
+}
+
+// __cxa_throw is defined to take its destructor as "void (*)(void *)" in the ABI.
+// CHECK-LABEL: define void @__cxa_throw({{.*}})
+// CHECK: call void {{%.*}}(ptr noundef {{%.*}}) [ "ptrauth"(i32 0, i64 0) ]
+extern "C" void __cxa_throw(void *exception, void *, void (*dtor)(void *)) {
+ dtor(exception);
+}
>From f116be80e35b6e82938a1dae994542d17b768ccf Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Sun, 14 Jul 2024 15:20:22 -0700
Subject: [PATCH 4/4] Update test to include test for type discriminated
function pointers
---
clang/test/CodeGenCXX/ptrauth-throw.cpp | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/clang/test/CodeGenCXX/ptrauth-throw.cpp b/clang/test/CodeGenCXX/ptrauth-throw.cpp
index 0e143433ee5a3..cea7226547e5a 100644
--- a/clang/test/CodeGenCXX/ptrauth-throw.cpp
+++ b/clang/test/CodeGenCXX/ptrauth-throw.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fcxx-exceptions -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fcxx-exceptions -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK
+// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios -fptrauth-calls -fcxx-exceptions -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECKDISC
class Foo {
public:
@@ -8,13 +9,21 @@ class Foo {
// CHECK-LABEL: define void @_Z1fv()
// CHECK: call void @__cxa_throw(ptr %{{.*}}, ptr @_ZTI3Foo, ptr ptrauth (ptr @_ZN3FooD1Ev, i32 0))
+
+// CHECKDISC-LABEL: define void @_Z1fv()
+// CHECKDISC: call void @__cxa_throw(ptr %{{.*}}, ptr @_ZTI3Foo, ptr ptrauth (ptr @_ZN3FooD1Ev, i32 0, i64 10942))
+
void f() {
throw Foo();
}
// __cxa_throw is defined to take its destructor as "void (*)(void *)" in the ABI.
// CHECK-LABEL: define void @__cxa_throw({{.*}})
-// CHECK: call void {{%.*}}(ptr noundef {{%.*}}) [ "ptrauth"(i32 0, i64 0) ]
+// CHECK: call void {{%.*}}(ptr noundef {{%.*}}) [ "ptrauth"(i32 0, i64 0) ]
+
+// CHECKDISC-LABEL: define void @__cxa_throw({{.*}})
+// CHECKDISC: call void {{%.*}}(ptr noundef {{%.*}}) [ "ptrauth"(i32 0, i64 10942) ]
+
extern "C" void __cxa_throw(void *exception, void *, void (*dtor)(void *)) {
dtor(exception);
}
More information about the cfe-commits
mailing list