diff options
author | Peter Collingbourne <peter@pcc.me.uk> | 2015-06-19 01:52:55 +0000 |
---|---|---|
committer | Peter Collingbourne <peter@pcc.me.uk> | 2015-06-19 01:52:55 +0000 |
commit | 271d42ab6a140f9bb897a49a6aa8627356890aa0 (patch) | |
tree | 58bd6c8432448d07f4f423d4b5aa9b2618212143 /lib/ubsan | |
parent | 7346ebc566c8a9394569951cfaf308eadb200564 (diff) |
Add control flow integrity diagnosis function to UBSan runtime library.
Also includes execution tests for the feature.
Differential Revision: http://reviews.llvm.org/D10269
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@240111 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/ubsan')
-rw-r--r-- | lib/ubsan/ubsan_handlers_cxx.cc | 39 | ||||
-rw-r--r-- | lib/ubsan/ubsan_handlers_cxx.h | 13 | ||||
-rw-r--r-- | lib/ubsan/ubsan_type_hash.cc | 21 | ||||
-rw-r--r-- | lib/ubsan/ubsan_type_hash.h | 5 |
4 files changed, 69 insertions, 9 deletions
diff --git a/lib/ubsan/ubsan_handlers_cxx.cc b/lib/ubsan/ubsan_handlers_cxx.cc index b3cda32a9..83b9939d3 100644 --- a/lib/ubsan/ubsan_handlers_cxx.cc +++ b/lib/ubsan/ubsan_handlers_cxx.cc @@ -37,7 +37,7 @@ static void HandleDynamicTypeCacheMiss( return; // Check if error report should be suppressed. - DynamicTypeInfo DTI = getDynamicTypeInfo((void*)Pointer); + DynamicTypeInfo DTI = getDynamicTypeInfoFromObject((void*)Pointer); if (DTI.isValid() && IsVptrCheckSuppressed(DTI.getMostDerivedTypeName())) return; @@ -82,4 +82,41 @@ void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort( HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts); } +static void HandleCFIBadType(CFIBadTypeData *Data, ValueHandle Vtable, + ReportOptions Opts) { + SourceLocation Loc = Data->Loc.acquire(); + ScopedReport R(Opts, Loc); + DynamicTypeInfo DTI = getDynamicTypeInfoFromVtable((void*)Vtable); + + static const char *TypeCheckKinds[] = { + "virtual call", + "non-virtual call", + "base-to-derived cast", + "cast to unrelated type", + }; + + Diag(Loc, DL_Error, "control flow integrity check for type %0 failed during " + "%1 (vtable address %2)") + << Data->Type << TypeCheckKinds[Data->TypeCheckKind] << (void *)Vtable; + + // If possible, say what type it actually points to. + if (!DTI.isValid()) + Diag(Vtable, DL_Note, "invalid vtable"); + else + Diag(Vtable, DL_Note, "vtable is of type %0") + << MangledName(DTI.getMostDerivedTypeName()); +} + +void __ubsan::__ubsan_handle_cfi_bad_type(CFIBadTypeData *Data, + ValueHandle Vtable) { + GET_REPORT_OPTIONS(false); + HandleCFIBadType(Data, Vtable, Opts); +} + +void __ubsan::__ubsan_handle_cfi_bad_type_abort(CFIBadTypeData *Data, + ValueHandle Vtable) { + GET_REPORT_OPTIONS(true); + HandleCFIBadType(Data, Vtable, Opts); +} + #endif // CAN_SANITIZE_UB diff --git a/lib/ubsan/ubsan_handlers_cxx.h b/lib/ubsan/ubsan_handlers_cxx.h index cb1bca78b..92050d99e 100644 --- a/lib/ubsan/ubsan_handlers_cxx.h +++ b/lib/ubsan/ubsan_handlers_cxx.h @@ -25,6 +25,12 @@ struct DynamicTypeCacheMissData { unsigned char TypeCheckKind; }; +struct CFIBadTypeData { + SourceLocation Loc; + const TypeDescriptor &Type; + unsigned char TypeCheckKind; +}; + /// \brief Handle a runtime type check failure, caused by an incorrect vptr. /// When this handler is called, all we know is that the type was not in the /// cache; this does not necessarily imply the existence of a bug. @@ -35,6 +41,13 @@ extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __ubsan_handle_dynamic_type_cache_miss_abort( DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash); +/// \brief Handle a control flow integrity check failure by printing a +/// diagnostic. +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +__ubsan_handle_cfi_bad_type(CFIBadTypeData *Data, ValueHandle Vtable); +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +__ubsan_handle_cfi_bad_type_abort(CFIBadTypeData *Data, ValueHandle Vtable); + } #endif // UBSAN_HANDLERS_H diff --git a/lib/ubsan/ubsan_type_hash.cc b/lib/ubsan/ubsan_type_hash.cc index 441f713b1..c130afdbc 100644 --- a/lib/ubsan/ubsan_type_hash.cc +++ b/lib/ubsan/ubsan_type_hash.cc @@ -196,11 +196,11 @@ struct VtablePrefix { /// The type_info object describing the most-derived class type. std::type_info *TypeInfo; }; -VtablePrefix *getVtablePrefix(void *Object) { - VtablePrefix **VptrPtr = reinterpret_cast<VtablePrefix**>(Object); - if (!*VptrPtr) +VtablePrefix *getVtablePrefix(void *Vtable) { + VtablePrefix *Vptr = reinterpret_cast<VtablePrefix*>(Vtable); + if (!Vptr) return 0; - VtablePrefix *Prefix = *VptrPtr - 1; + VtablePrefix *Prefix = Vptr - 1; if (Prefix->Offset > 0 || !Prefix->TypeInfo) // This can't possibly be a valid vtable. return 0; @@ -220,7 +220,8 @@ bool __ubsan::checkDynamicType(void *Object, void *Type, HashValue Hash) { return true; } - VtablePrefix *Vtable = getVtablePrefix(Object); + void *VtablePtr = *reinterpret_cast<void **>(Object); + VtablePrefix *Vtable = getVtablePrefix(VtablePtr); if (!Vtable) return false; @@ -240,8 +241,14 @@ bool __ubsan::checkDynamicType(void *Object, void *Type, HashValue Hash) { return true; } -__ubsan::DynamicTypeInfo __ubsan::getDynamicTypeInfo(void *Object) { - VtablePrefix *Vtable = getVtablePrefix(Object); +__ubsan::DynamicTypeInfo __ubsan::getDynamicTypeInfoFromObject(void *Object) { + void *VtablePtr = *reinterpret_cast<void **>(Object); + return getDynamicTypeInfoFromVtable(VtablePtr); +} + +__ubsan::DynamicTypeInfo +__ubsan::getDynamicTypeInfoFromVtable(void *VtablePtr) { + VtablePrefix *Vtable = getVtablePrefix(VtablePtr); if (!Vtable) return DynamicTypeInfo(0, 0, 0); const abi::__class_type_info *ObjectType = findBaseAtOffset( diff --git a/lib/ubsan/ubsan_type_hash.h b/lib/ubsan/ubsan_type_hash.h index 58ecd3de9..695fed905 100644 --- a/lib/ubsan/ubsan_type_hash.h +++ b/lib/ubsan/ubsan_type_hash.h @@ -41,7 +41,10 @@ public: }; /// \brief Get information about the dynamic type of an object. -DynamicTypeInfo getDynamicTypeInfo(void *Object); +DynamicTypeInfo getDynamicTypeInfoFromObject(void *Object); + +/// \brief Get information about the dynamic type of an object from its vtable. +DynamicTypeInfo getDynamicTypeInfoFromVtable(void *Vtable); /// \brief Check whether the dynamic type of \p Object has a \p Type subobject /// at offset 0. |