[compiler-rt] r271560 - UBSan: crash less often on corrupted Vtables.

Ivan Krasin via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 2 11:36:12 PDT 2016


Author: krasin
Date: Thu Jun  2 13:36:12 2016
New Revision: 271560

URL: http://llvm.org/viewvc/llvm-project?rev=271560&view=rev
Log:
UBSan: crash less often on corrupted Vtables.

Summary:
This CL adds a weak check for a Vtable prefix: for a well-formed
Vtable, we require the prefix to be within [-1<<20; 1<<20].

Practically, this solves most of the known cases when UBSan segfaults
without providing any useful diagnostics.

Reviewers: pcc

Subscribers: kubabrecka

Differential Revision: http://reviews.llvm.org/D19750

Added:
    compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp
Modified:
    compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc
    compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h
    compiler-rt/trunk/lib/ubsan/ubsan_type_hash_itanium.cc

Modified: compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc?rev=271560&r1=271559&r2=271560&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc Thu Jun  2 13:36:12 2016
@@ -55,11 +55,17 @@ static bool HandleDynamicTypeCacheMiss(
     << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
 
   // If possible, say what type it actually points to.
-  if (!DTI.isValid())
-    Diag(Pointer, DL_Note, "object has invalid vptr")
-        << TypeName(DTI.getMostDerivedTypeName())
-        << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
-  else if (!DTI.getOffset())
+  if (!DTI.isValid()) {
+    if (DTI.getOffset() < -VptrMaxOffsetToTop || DTI.getOffset() > VptrMaxOffsetToTop) {
+      Diag(Pointer, DL_Note, "object has a possibly invalid vptr: abs(offset to top) too big")
+          << TypeName(DTI.getMostDerivedTypeName())
+          << Range(Pointer, Pointer + sizeof(uptr), "possibly invalid vptr");
+    } else {
+      Diag(Pointer, DL_Note, "object has invalid vptr")
+          << TypeName(DTI.getMostDerivedTypeName())
+          << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
+    }
+  } else if (!DTI.getOffset())
     Diag(Pointer, DL_Note, "object is of type %0")
         << TypeName(DTI.getMostDerivedTypeName())
         << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");

Modified: compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h?rev=271560&r1=271559&r2=271560&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_type_hash.h Thu Jun  2 13:36:12 2016
@@ -53,6 +53,10 @@ bool checkDynamicType(void *Object, void
 
 const unsigned VptrTypeCacheSize = 128;
 
+/// A sanity check for Vtable. Offsets to top must be reasonably small
+/// numbers (by absolute value). It's a weak check for Vtable corruption.
+const int VptrMaxOffsetToTop = 1<<20;
+
 /// \brief A cache of the results of checkDynamicType. \c checkDynamicType would
 /// return \c true (modulo hash collisions) if
 /// \code

Modified: compiler-rt/trunk/lib/ubsan/ubsan_type_hash_itanium.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_type_hash_itanium.cc?rev=271560&r1=271559&r2=271560&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_type_hash_itanium.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_type_hash_itanium.cc Thu Jun  2 13:36:12 2016
@@ -221,6 +221,10 @@ bool __ubsan::checkDynamicType(void *Obj
   VtablePrefix *Vtable = getVtablePrefix(VtablePtr);
   if (!Vtable)
     return false;
+  if (Vtable->Offset < -VptrMaxOffsetToTop || Vtable->Offset > VptrMaxOffsetToTop) {
+    // Too large or too small offset are signs of Vtable corruption.
+    return false;
+  }
 
   // Check that this is actually a type_info object for a class type.
   abi::__class_type_info *Derived =
@@ -243,6 +247,8 @@ __ubsan::getDynamicTypeInfoFromVtable(vo
   VtablePrefix *Vtable = getVtablePrefix(VtablePtr);
   if (!Vtable)
     return DynamicTypeInfo(0, 0, 0);
+  if (Vtable->Offset < -VptrMaxOffsetToTop || Vtable->Offset > VptrMaxOffsetToTop)
+    return DynamicTypeInfo(0, Vtable->Offset, 0);
   const abi::__class_type_info *ObjectType = findBaseAtOffset(
     static_cast<const abi::__class_type_info*>(Vtable->TypeInfo),
     -Vtable->Offset);

Added: compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp?rev=271560&view=auto
==============================================================================
--- compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp (added)
+++ compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp Thu Jun  2 13:36:12 2016
@@ -0,0 +1,41 @@
+// 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: win32
+// REQUIRES: stable-runtime, cxxabi
+#include <cstddef>
+
+#include <typeinfo>
+
+struct S {
+  S() {}
+  ~S() {}
+  virtual int v() { return 0; }
+};
+
+// See the proper definition in ubsan_type_hash_itanium.cc
+struct VtablePrefix {
+  signed long Offset;
+  std::type_info *TypeInfo;
+};
+
+int main(int argc, char **argv) {
+  // Test that we don't crash on corrupted vtable when
+  // offset is too large or too small.
+  S Obj;
+  void *Ptr = &Obj;
+  VtablePrefix* RealPrefix = reinterpret_cast<VtablePrefix*>(
+      *reinterpret_cast<void**>(Ptr)) - 1;
+
+  VtablePrefix Prefix[2];
+  Prefix[0].Offset = 1<<21; // Greater than VptrMaxOffset
+  Prefix[0].TypeInfo = RealPrefix->TypeInfo;
+
+  // Hack Vtable ptr for Obj.
+  *reinterpret_cast<void**>(Ptr) = static_cast<void*>(&Prefix[1]);
+
+  // 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
+  S* Ptr2 = reinterpret_cast<S*>(Ptr);
+  return Ptr2->v();
+}




More information about the llvm-commits mailing list