[compiler-rt] r259717 - [cfi] Safe handling of unaddressable vtable pointers (compiler-rt).

Evgeniy Stepanov via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 3 14:19:05 PST 2016


Author: eugenis
Date: Wed Feb  3 16:19:04 2016
New Revision: 259717

URL: http://llvm.org/viewvc/llvm-project?rev=259717&view=rev
Log:
[cfi] Safe handling of unaddressable vtable pointers (compiler-rt).

Avoid crashing when printing diagnostics for vtable-related CFI
errors. In diagnostic mode, the frontend does an additional check of
the vtable pointer against the set of all known vtable addresses and
lets the runtime handler know if it is safe to inspect the vtable.

http://reviews.llvm.org/D16824

Added:
    compiler-rt/trunk/test/cfi/target_uninstrumented.cpp
Modified:
    compiler-rt/trunk/lib/cfi/cfi.cc
    compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc
    compiler-rt/trunk/lib/ubsan/ubsan_handlers.h
    compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc
    compiler-rt/trunk/test/cfi/cross-dso/target_out_of_bounds.cpp

Modified: compiler-rt/trunk/lib/cfi/cfi.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/cfi/cfi.cc?rev=259717&r1=259716&r2=259717&view=diff
==============================================================================
--- compiler-rt/trunk/lib/cfi/cfi.cc (original)
+++ compiler-rt/trunk/lib/cfi/cfi.cc Wed Feb  3 16:19:04 2016
@@ -307,7 +307,7 @@ ALWAYS_INLINE void CfiSlowPathCommon(u64
 #ifdef CFI_ENABLE_DIAG
     if (DiagData) {
       __ubsan_handle_cfi_check_fail(
-          reinterpret_cast<__ubsan::CFICheckFailData *>(DiagData), Addr);
+          reinterpret_cast<__ubsan::CFICheckFailData *>(DiagData), Addr, false);
       return;
     }
 #endif

Modified: compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc?rev=259717&r1=259716&r2=259717&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc Wed Feb  3 16:19:04 2016
@@ -551,31 +551,33 @@ namespace __ubsan {
 #ifdef UBSAN_CAN_USE_CXXABI
 SANITIZER_WEAK_ATTRIBUTE
 void HandleCFIBadType(CFICheckFailData *Data, ValueHandle Vtable,
-                      ReportOptions Opts);
+                      bool ValidVtable, ReportOptions Opts);
 #else
 static void HandleCFIBadType(CFICheckFailData *Data, ValueHandle Vtable,
-                             ReportOptions Opts) {
+                             bool ValidVtable, ReportOptions Opts) {
   Die();
 }
 #endif
 }  // namespace __ubsan
 
 void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,
-                                           ValueHandle Value) {
+                                            ValueHandle Value,
+                                            uptr ValidVtable) {
   GET_REPORT_OPTIONS(false);
   if (Data->CheckKind == CFITCK_ICall)
     handleCFIBadIcall(Data, Value, Opts);
   else
-    HandleCFIBadType(Data, Value, Opts);
+    HandleCFIBadType(Data, Value, ValidVtable, Opts);
 }
 
 void __ubsan::__ubsan_handle_cfi_check_fail_abort(CFICheckFailData *Data,
-                                                 ValueHandle Value) {
+                                                  ValueHandle Value,
+                                                  uptr ValidVtable) {
   GET_REPORT_OPTIONS(true);
   if (Data->CheckKind == CFITCK_ICall)
     handleCFIBadIcall(Data, Value, Opts);
   else
-    HandleCFIBadType(Data, Value, Opts);
+    HandleCFIBadType(Data, Value, ValidVtable, Opts);
   Die();
 }
 

Modified: compiler-rt/trunk/lib/ubsan/ubsan_handlers.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_handlers.h?rev=259717&r1=259716&r2=259717&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_handlers.h (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_handlers.h Wed Feb  3 16:19:04 2016
@@ -165,8 +165,8 @@ struct CFICheckFailData {
 };
 
 /// \brief Handle control flow integrity failures.
-RECOVERABLE(cfi_check_fail, CFICheckFailData *Data, ValueHandle Function)
-
+RECOVERABLE(cfi_check_fail, CFICheckFailData *Data, ValueHandle Function,
+            uptr VtableIsValid)
 }
 
 #endif // UBSAN_HANDLERS_H

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=259717&r1=259716&r2=259717&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc Wed Feb  3 16:19:04 2016
@@ -90,7 +90,7 @@ void __ubsan::__ubsan_handle_dynamic_typ
 
 namespace __ubsan {
 void HandleCFIBadType(CFICheckFailData *Data, ValueHandle Vtable,
-                      ReportOptions Opts) {
+                      bool ValidVtable, ReportOptions Opts) {
   SourceLocation Loc = Data->Loc.acquire();
   ErrorType ET = ErrorType::CFIBadType;
 
@@ -98,7 +98,9 @@ void HandleCFIBadType(CFICheckFailData *
     return;
 
   ScopedReport R(Opts, Loc, ET);
-  DynamicTypeInfo DTI = getDynamicTypeInfoFromVtable((void *)Vtable);
+  DynamicTypeInfo DTI = ValidVtable
+                            ? getDynamicTypeInfoFromVtable((void *)Vtable)
+                            : DynamicTypeInfo(0, 0, 0);
 
   const char *CheckKindStr;
   switch (Data->CheckKind) {
@@ -123,11 +125,16 @@ void HandleCFIBadType(CFICheckFailData *
       << Data->Type << CheckKindStr << (void *)Vtable;
 
   // If possible, say what type it actually points to.
-  if (!DTI.isValid())
-    Diag(Vtable, DL_Note, "invalid vtable");
-  else
+  if (!DTI.isValid()) {
+    const char *module = Symbolizer::GetOrInit()->GetModuleNameForPc(Vtable);
+    if (module)
+      Diag(Vtable, DL_Note, "invalid vtable in module %0") << module;
+    else
+      Diag(Vtable, DL_Note, "invalid vtable");
+  } else {
     Diag(Vtable, DL_Note, "vtable is of type %0")
         << TypeName(DTI.getMostDerivedTypeName());
+  }
 }
 }  // namespace __ubsan
 

Modified: compiler-rt/trunk/test/cfi/cross-dso/target_out_of_bounds.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/cfi/cross-dso/target_out_of_bounds.cpp?rev=259717&r1=259716&r2=259717&view=diff
==============================================================================
--- compiler-rt/trunk/test/cfi/cross-dso/target_out_of_bounds.cpp (original)
+++ compiler-rt/trunk/test/cfi/cross-dso/target_out_of_bounds.cpp Wed Feb  3 16:19:04 2016
@@ -1,5 +1,12 @@
-// RUN: %clangxx_cfi_dso_diag %s -o %t
-// RUN: %expect_crash %t 2>&1 | FileCheck %s
+// RUN: %clangxx_cfi_dso_diag -std=c++11 %s -o %t
+// RUN: %t zero 2>&1 | FileCheck --check-prefix=CHECK-ZERO %s
+// RUN: %t unaddressable 2>&1 | FileCheck --check-prefix=CHECK-UNADDR %s
+// RUN: %t 2>&1 | FileCheck --check-prefix=CHECK-TYPEINFO %s
+
+// RUN: %clangxx_cfi_diag -std=c++11 %s -o %t2
+// RUN: %t2 zero 2>&1 | FileCheck --check-prefix=CHECK-ZERO %s
+// RUN: %t2 unaddressable 2>&1 | FileCheck --check-prefix=CHECK-UNADDR %s
+// RUN: %t2 2>&1 | FileCheck --check-prefix=CHECK-TYPEINFO %s
 
 // REQUIRES: cxxabi
 
@@ -7,6 +14,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/mman.h>
 
 struct A {
   virtual void f();
@@ -15,18 +23,42 @@ struct A {
 void A::f() {}
 
 int main(int argc, char *argv[]) {
-  // Create an object with a vtable outside of any known DSO, but still in an
-  // addressable area. Current implementation of handlers in UBSan is not robust
-  // enough to handle unaddressable vtables. TODO: fix this.
-  void *empty = calloc(1, 128);
-  uintptr_t v = (uintptr_t)empty + 64;
   char *volatile p = reinterpret_cast<char *>(new A());
-  for (uintptr_t *q = (uintptr_t *)p; q < (uintptr_t *)(p + sizeof(A)); ++q)
-    *q = v;
+  if (argc > 1 && strcmp(argv[1], "unaddressable") == 0) {
+    void *vtable = mmap(nullptr, 4096, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+    // Create an object with a vtable in an unaddressable memory region.
+    *(uintptr_t *)p = (uintptr_t)vtable + 64;
+    // CHECK-UNADDR: runtime error: control flow integrity check for type 'A' failed during cast
+    // CHECK-UNADDR: note: invalid vtable
+    // CHECK-UNADDR: <memory cannot be printed>
+    // CHECK-UNADDR: runtime error: control flow integrity check for type 'A' failed during cast
+    // CHECK-UNADDR: note: invalid vtable
+    // CHECK-UNADDR: <memory cannot be printed>
+  } else if (argc > 1 && strcmp(argv[1], "zero") == 0) {
+    // Create an object with a vtable outside of any known DSO, but still in an
+    // addressable area.
+    void *vtable = calloc(1, 128);
+    *(uintptr_t *)p = (uintptr_t)vtable + 64;
+    // CHECK-ZERO: runtime error: control flow integrity check for type 'A' failed during cast
+    // CHECK-ZERO: note: invalid vtable
+    // CHECK-ZERO: 00 00 00 00 00 00 00 00
+    // CHECK-ZERO: runtime error: control flow integrity check for type 'A' failed during cast
+    // CHECK-ZERO: note: invalid vtable
+    // CHECK-ZERO: 00 00 00 00 00 00 00 00
+  } else {
+    // Create an object with a seemingly fine vtable, but with an unaddressable
+    // typeinfo pointer.
+    void *vtable = calloc(1, 128);
+    memset(vtable, 0xFE, 128);
+    *(uintptr_t *)p = (uintptr_t)vtable + 64;
+    // CHECK-TYPEINFO: runtime error: control flow integrity check for type 'A' failed during cast
+    // CHECK-TYPEINFO: note: invalid vtable
+    // CHECK-TYPEINFO: fe fe fe fe fe fe fe fe
+    // CHECK-TYPEINFO: runtime error: control flow integrity check for type 'A' failed during cast
+    // CHECK-TYPEINFO: note: invalid vtable
+    // CHECK-TYPEINFO: fe fe fe fe fe fe fe fe
+  }
 
-  // CHECK: runtime error: control flow integrity check for type 'A' failed during cast
   A *volatile pa = reinterpret_cast<A *>(p);
-
-  // CHECK: untime error: control flow integrity check for type 'A' failed during virtual call
-  pa->f();
+  pa = reinterpret_cast<A *>(p);
 }

Added: compiler-rt/trunk/test/cfi/target_uninstrumented.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/cfi/target_uninstrumented.cpp?rev=259717&view=auto
==============================================================================
--- compiler-rt/trunk/test/cfi/target_uninstrumented.cpp (added)
+++ compiler-rt/trunk/test/cfi/target_uninstrumented.cpp Wed Feb  3 16:19:04 2016
@@ -0,0 +1,44 @@
+// RUN: %clangxx -g -DSHARED_LIB %s -fPIC -shared -o %T/target_uninstrumented-so.so
+// RUN: %clangxx_cfi_diag -g %s -o %t %T/target_uninstrumented-so.so
+// RUN: %t 2>&1 | FileCheck %s
+
+// REQUIRES: cxxabi
+
+#include <stdio.h>
+#include <string.h>
+
+struct A {
+  virtual void f();
+};
+
+void *create_B();
+
+#ifdef SHARED_LIB
+
+struct B {
+  virtual void f();
+};
+void B::f() {}
+
+void *create_B() {
+  return (void *)(new B());
+}
+
+#else
+
+void A::f() {}
+
+int main(int argc, char *argv[]) {
+  void *p = create_B();
+  // CHECK: runtime error: control flow integrity check for type 'A' failed during cast to unrelated type
+  // CHECK: invalid vtable in module {{.*}}target_uninstrumented-so.so
+  A *a = (A *)p;
+  memset(p, 0, sizeof(A));
+  // CHECK: runtime error: control flow integrity check for type 'A' failed during cast to unrelated type
+  // CHECK-NOT: invalid vtable in module
+  // CHECK: invalid vtable
+  a = (A *)p;
+  // CHECK: done
+  fprintf(stderr, "done %p\n", a);
+}
+#endif




More information about the llvm-commits mailing list