diff --git a/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp b/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp --- a/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp +++ b/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp @@ -17,6 +17,10 @@ #include "sanitizer_common/sanitizer_common.h" +#if __has_feature(ptrauth_calls) +#include +#endif + // The following are intended to be binary compatible with the definitions // given in the Itanium ABI. We make no attempt to be ODR-compatible with // those definitions, since existing ABI implementations aren't. @@ -194,6 +198,9 @@ std::type_info *TypeInfo; }; VtablePrefix *getVtablePrefix(void *Vtable) { +#if __has_feature(ptrauth_calls) + Vtable = ptrauth_auth_data(Vtable, ptrauth_key_cxx_vtable_pointer, 0); +#endif VtablePrefix *Vptr = reinterpret_cast(Vtable); VtablePrefix *Prefix = Vptr - 1; if (!IsAccessibleMemoryRange((uptr)Prefix, sizeof(VtablePrefix))) diff --git a/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp b/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp --- a/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp +++ b/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp @@ -1,12 +1,15 @@ -// RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr,null -g %s -O3 -o %t +// RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr -g %s -O3 -o %t // RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-CORRUPTED-VTABLE --strict-whitespace // UNSUPPORTED: windows-msvc // REQUIRES: stable-runtime, cxxabi -#include #include +#if __has_feature(ptrauth_calls) +#include +#endif + struct S { S() {} ~S() {} @@ -24,15 +27,23 @@ // offset is too large or too small. S Obj; void *Ptr = &Obj; - VtablePrefix* RealPrefix = reinterpret_cast( - *reinterpret_cast(Ptr)) - 1; + void *VtablePtr = *reinterpret_cast(Ptr); +#if __has_feature(ptrauth_calls) + VtablePtr = ptrauth_strip(VtablePtr, 0); +#endif + VtablePrefix* Prefix = reinterpret_cast(VtablePtr) - 1; - VtablePrefix Prefix[2]; - Prefix[0].Offset = 1<<21; // Greater than VptrMaxOffset - Prefix[0].TypeInfo = RealPrefix->TypeInfo; + VtablePrefix FakePrefix[2]; + FakePrefix[0].Offset = 1<<21; // Greater than VptrMaxOffset + FakePrefix[0].TypeInfo = Prefix->TypeInfo; // Hack Vtable ptr for Obj. - *reinterpret_cast(Ptr) = static_cast(&Prefix[1]); + void *FakeVtablePtr = static_cast(&FakePrefix[1]); +#if __has_feature(ptrauth_calls) + FakeVtablePtr = ptrauth_sign_unauthenticated( + FakeVtablePtr, ptrauth_key_cxx_vtable_pointer, 0); +#endif + *reinterpret_cast(Ptr) = FakeVtablePtr; // CHECK-CORRUPTED-VTABLE: vptr-corrupted-vtable-itanium.cpp:[[@LINE+3]]:16: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'S' // CHECK-CORRUPTED-VTABLE-NEXT: [[PTR]]: note: object has a possibly invalid vptr: abs(offset to top) too big diff --git a/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-ptrauth-unauthenticated.cpp b/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-ptrauth-unauthenticated.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-ptrauth-unauthenticated.cpp @@ -0,0 +1,31 @@ +// Test that we don't crash for vtable pointers with an invalid ptrauth +// signature which includes unauthenticated vtable pointers. + +// RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr -g %s -O3 -o %t +// RUN: not %run %t 2>&1 | FileCheck %s + +// TODO(yln): introduce 'ptrauth' lit feature +// REQUIRES: stable-runtime, cxxabi, arch=arm64e + +#include +#include + +struct S { + S() {} + ~S() {} + virtual int v() { return 0; } +}; + +int main(int argc, char **argv) { + S Obj; + void *Ptr = &Obj; + void **VtablePtrPtr = reinterpret_cast(&Obj); + // Hack Obj: the unauthenticated Vtable ptr will trigger an auth failure in the runtime. + void *UnauthenticatedVtablePtr = ptrauth_strip(*VtablePtrPtr, 0); + *VtablePtrPtr = UnauthenticatedVtablePtr; + + // CHECK: vptr-ptrauth-unauthenticated.cpp:[[@LINE+3]]:16: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'S' + // CHECK: [[PTR]]: note: object has invalid vptr + S *Ptr2 = reinterpret_cast(Ptr); + return Ptr2->v(); +}