[UBSan] Fix vptr checks on arm64e

Fix UBSan's vptr checks in the presence of arm64e pointer signing.

Radar-Id: rdar://61786404

Reviewed By: vsk

Differential Revision: https://reviews.llvm.org/D78230
This commit is contained in:
Julian Lettner 2020-04-14 12:48:58 -07:00
parent 63725df1d6
commit 80022ae2b5
3 changed files with 57 additions and 8 deletions

View File

@ -17,6 +17,10 @@
#include "sanitizer_common/sanitizer_common.h"
#if __has_feature(ptrauth_calls)
#include <ptrauth.h>
#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 @@ struct VtablePrefix {
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<VtablePrefix*>(Vtable);
VtablePrefix *Prefix = Vptr - 1;
if (!IsAccessibleMemoryRange((uptr)Prefix, sizeof(VtablePrefix)))

View File

@ -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 <cstddef>
#include <typeinfo>
#if __has_feature(ptrauth_calls)
#include <ptrauth.h>
#endif
struct S {
S() {}
~S() {}
@ -24,15 +27,23 @@ int main(int argc, char **argv) {
// offset is too large or too small.
S Obj;
void *Ptr = &Obj;
VtablePrefix* RealPrefix = reinterpret_cast<VtablePrefix*>(
*reinterpret_cast<void**>(Ptr)) - 1;
void *VtablePtr = *reinterpret_cast<void**>(Ptr);
#if __has_feature(ptrauth_calls)
VtablePtr = ptrauth_strip(VtablePtr, 0);
#endif
VtablePrefix* Prefix = reinterpret_cast<VtablePrefix*>(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<void**>(Ptr) = static_cast<void*>(&Prefix[1]);
void *FakeVtablePtr = static_cast<void*>(&FakePrefix[1]);
#if __has_feature(ptrauth_calls)
FakeVtablePtr = ptrauth_sign_unauthenticated(
FakeVtablePtr, ptrauth_key_cxx_vtable_pointer, 0);
#endif
*reinterpret_cast<void**>(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

View File

@ -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 <typeinfo>
#include <ptrauth.h>
struct S {
S() {}
~S() {}
virtual int v() { return 0; }
};
int main(int argc, char **argv) {
S Obj;
void *Ptr = &Obj;
void **VtablePtrPtr = reinterpret_cast<void **>(&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<S *>(Ptr);
return Ptr2->v();
}