1 1.1 mrg //===-- ubsan_handlers_cxx.cpp --------------------------------------------===// 2 1.1 mrg // 3 1.1 mrg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 1.1 mrg // See https://llvm.org/LICENSE.txt for license information. 5 1.1 mrg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 1.1 mrg // 7 1.1 mrg //===----------------------------------------------------------------------===// 8 1.1 mrg // 9 1.1 mrg // Error logging entry points for the UBSan runtime, which are only used for C++ 10 1.1 mrg // compilations. This file is permitted to use language features which require 11 1.1 mrg // linking against a C++ ABI library. 12 1.1 mrg // 13 1.1 mrg //===----------------------------------------------------------------------===// 14 1.1 mrg 15 1.1 mrg #include "ubsan_platform.h" 16 1.1 mrg #if CAN_SANITIZE_UB 17 1.1 mrg #include "ubsan_handlers.h" 18 1.1 mrg #include "ubsan_handlers_cxx.h" 19 1.1 mrg #include "ubsan_diag.h" 20 1.1 mrg #include "ubsan_type_hash.h" 21 1.1 mrg 22 1.1 mrg #include "sanitizer_common/sanitizer_common.h" 23 1.1 mrg #include "sanitizer_common/sanitizer_suppressions.h" 24 1.1 mrg 25 1.1 mrg using namespace __sanitizer; 26 1.1 mrg using namespace __ubsan; 27 1.1 mrg 28 1.1 mrg namespace __ubsan { 29 1.1 mrg extern const char *TypeCheckKinds[]; 30 1.1 mrg } 31 1.1 mrg 32 1.1 mrg // Returns true if UBSan has printed an error report. 33 1.1 mrg static bool HandleDynamicTypeCacheMiss( 34 1.1 mrg DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash, 35 1.1 mrg ReportOptions Opts) { 36 1.1 mrg if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash)) 37 1.1 mrg // Just a cache miss. The type matches after all. 38 1.1 mrg return false; 39 1.1 mrg 40 1.1 mrg // Check if error report should be suppressed. 41 1.1 mrg DynamicTypeInfo DTI = getDynamicTypeInfoFromObject((void*)Pointer); 42 1.1 mrg if (DTI.isValid() && IsVptrCheckSuppressed(DTI.getMostDerivedTypeName())) 43 1.1 mrg return false; 44 1.1 mrg 45 1.1 mrg SourceLocation Loc = Data->Loc.acquire(); 46 1.1 mrg ErrorType ET = ErrorType::DynamicTypeMismatch; 47 1.1 mrg if (ignoreReport(Loc, Opts, ET)) 48 1.1 mrg return false; 49 1.1 mrg 50 1.1 mrg ScopedReport R(Opts, Loc, ET); 51 1.1 mrg 52 1.1 mrg Diag(Loc, DL_Error, ET, 53 1.1 mrg "%0 address %1 which does not point to an object of type %2") 54 1.1 mrg << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type; 55 1.1 mrg 56 1.1 mrg // If possible, say what type it actually points to. 57 1.1 mrg if (!DTI.isValid()) { 58 1.1 mrg if (DTI.getOffset() < -VptrMaxOffsetToTop || DTI.getOffset() > VptrMaxOffsetToTop) { 59 1.1 mrg Diag(Pointer, DL_Note, ET, 60 1.1 mrg "object has a possibly invalid vptr: abs(offset to top) too big") 61 1.1 mrg << TypeName(DTI.getMostDerivedTypeName()) 62 1.1 mrg << Range(Pointer, Pointer + sizeof(uptr), "possibly invalid vptr"); 63 1.1 mrg } else { 64 1.1 mrg Diag(Pointer, DL_Note, ET, "object has invalid vptr") 65 1.1 mrg << TypeName(DTI.getMostDerivedTypeName()) 66 1.1 mrg << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr"); 67 1.1 mrg } 68 1.1 mrg } else if (!DTI.getOffset()) 69 1.1 mrg Diag(Pointer, DL_Note, ET, "object is of type %0") 70 1.1 mrg << TypeName(DTI.getMostDerivedTypeName()) 71 1.1 mrg << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0"); 72 1.1 mrg else 73 1.1 mrg // FIXME: Find the type at the specified offset, and include that 74 1.1 mrg // in the note. 75 1.1 mrg Diag(Pointer - DTI.getOffset(), DL_Note, ET, 76 1.1 mrg "object is base class subobject at offset %0 within object of type %1") 77 1.1 mrg << DTI.getOffset() << TypeName(DTI.getMostDerivedTypeName()) 78 1.1 mrg << TypeName(DTI.getSubobjectTypeName()) 79 1.1 mrg << Range(Pointer, Pointer + sizeof(uptr), 80 1.1 mrg "vptr for %2 base class of %1"); 81 1.1 mrg return true; 82 1.1 mrg } 83 1.1 mrg 84 1.1 mrg void __ubsan::__ubsan_handle_dynamic_type_cache_miss( 85 1.1 mrg DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) { 86 1.1 mrg GET_REPORT_OPTIONS(false); 87 1.1 mrg HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts); 88 1.1 mrg } 89 1.1 mrg void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort( 90 1.1 mrg DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) { 91 1.1 mrg // Note: -fsanitize=vptr is always recoverable. 92 1.1 mrg GET_REPORT_OPTIONS(false); 93 1.1 mrg if (HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts)) 94 1.1 mrg Die(); 95 1.1 mrg } 96 1.1 mrg 97 1.1 mrg namespace __ubsan { 98 1.1 mrg void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, 99 1.1 mrg bool ValidVtable, ReportOptions Opts) { 100 1.1 mrg SourceLocation Loc = Data->Loc.acquire(); 101 1.1 mrg ErrorType ET = ErrorType::CFIBadType; 102 1.1 mrg 103 1.1 mrg if (ignoreReport(Loc, Opts, ET)) 104 1.1 mrg return; 105 1.1 mrg 106 1.1 mrg ScopedReport R(Opts, Loc, ET); 107 1.1 mrg DynamicTypeInfo DTI = ValidVtable 108 1.1 mrg ? getDynamicTypeInfoFromVtable((void *)Vtable) 109 1.1 mrg : DynamicTypeInfo(0, 0, 0); 110 1.1 mrg 111 1.1 mrg const char *CheckKindStr; 112 1.1 mrg switch (Data->CheckKind) { 113 1.1 mrg case CFITCK_VCall: 114 1.1 mrg CheckKindStr = "virtual call"; 115 1.1 mrg break; 116 1.1 mrg case CFITCK_NVCall: 117 1.1 mrg CheckKindStr = "non-virtual call"; 118 1.1 mrg break; 119 1.1 mrg case CFITCK_DerivedCast: 120 1.1 mrg CheckKindStr = "base-to-derived cast"; 121 1.1 mrg break; 122 1.1 mrg case CFITCK_UnrelatedCast: 123 1.1 mrg CheckKindStr = "cast to unrelated type"; 124 1.1 mrg break; 125 1.1 mrg case CFITCK_VMFCall: 126 1.1 mrg CheckKindStr = "virtual pointer to member function call"; 127 1.1 mrg break; 128 1.1 mrg case CFITCK_ICall: 129 1.1 mrg case CFITCK_NVMFCall: 130 1.1 mrg Die(); 131 1.1 mrg } 132 1.1 mrg 133 1.1 mrg Diag(Loc, DL_Error, ET, 134 1.1 mrg "control flow integrity check for type %0 failed during " 135 1.1 mrg "%1 (vtable address %2)") 136 1.1 mrg << Data->Type << CheckKindStr << (void *)Vtable; 137 1.1 mrg 138 1.1 mrg // If possible, say what type it actually points to. 139 1.1 mrg if (!DTI.isValid()) 140 1.1 mrg Diag(Vtable, DL_Note, ET, "invalid vtable"); 141 1.1 mrg else 142 1.1 mrg Diag(Vtable, DL_Note, ET, "vtable is of type %0") 143 1.1 mrg << TypeName(DTI.getMostDerivedTypeName()); 144 1.1 mrg 145 1.1 mrg // If the failure involved different DSOs for the check location and vtable, 146 1.1 mrg // report the DSO names. 147 1.1 mrg const char *DstModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Vtable); 148 1.1 mrg if (!DstModule) 149 1.1 mrg DstModule = "(unknown)"; 150 1.1 mrg 151 1.1 mrg const char *SrcModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Opts.pc); 152 1.1 mrg if (!SrcModule) 153 1.1 mrg SrcModule = "(unknown)"; 154 1.1 mrg 155 1.1 mrg if (internal_strcmp(SrcModule, DstModule)) 156 1.1 mrg Diag(Loc, DL_Note, ET, "check failed in %0, vtable located in %1") 157 1.1 mrg << SrcModule << DstModule; 158 1.1 mrg } 159 1.1 mrg 160 1.1 mrg static bool handleFunctionTypeMismatch(FunctionTypeMismatchData *Data, 161 1.1 mrg ValueHandle Function, 162 1.1 mrg ValueHandle calleeRTTI, 163 1.1 mrg ValueHandle fnRTTI, ReportOptions Opts) { 164 1.1 mrg if (checkTypeInfoEquality(reinterpret_cast<void *>(calleeRTTI), 165 1.1 mrg reinterpret_cast<void *>(fnRTTI))) 166 1.1 mrg return false; 167 1.1 mrg 168 1.1 mrg SourceLocation CallLoc = Data->Loc.acquire(); 169 1.1 mrg ErrorType ET = ErrorType::FunctionTypeMismatch; 170 1.1 mrg 171 1.1 mrg if (ignoreReport(CallLoc, Opts, ET)) 172 1.1 mrg return true; 173 1.1 mrg 174 1.1 mrg ScopedReport R(Opts, CallLoc, ET); 175 1.1 mrg 176 1.1 mrg SymbolizedStackHolder FLoc(getSymbolizedLocation(Function)); 177 1.1 mrg const char *FName = FLoc.get()->info.function; 178 1.1 mrg if (!FName) 179 1.1 mrg FName = "(unknown)"; 180 1.1 mrg 181 1.1 mrg Diag(CallLoc, DL_Error, ET, 182 1.1 mrg "call to function %0 through pointer to incorrect function type %1") 183 1.1 mrg << FName << Data->Type; 184 1.1 mrg Diag(FLoc, DL_Note, ET, "%0 defined here") << FName; 185 1.1 mrg return true; 186 1.1 mrg } 187 1.1 mrg 188 1.1 mrg void __ubsan_handle_function_type_mismatch_v1(FunctionTypeMismatchData *Data, 189 1.1 mrg ValueHandle Function, 190 1.1 mrg ValueHandle calleeRTTI, 191 1.1 mrg ValueHandle fnRTTI) { 192 1.1 mrg GET_REPORT_OPTIONS(false); 193 1.1 mrg handleFunctionTypeMismatch(Data, Function, calleeRTTI, fnRTTI, Opts); 194 1.1 mrg } 195 1.1 mrg 196 1.1 mrg void __ubsan_handle_function_type_mismatch_v1_abort( 197 1.1 mrg FunctionTypeMismatchData *Data, ValueHandle Function, 198 1.1 mrg ValueHandle calleeRTTI, ValueHandle fnRTTI) { 199 1.1 mrg GET_REPORT_OPTIONS(true); 200 1.1 mrg if (handleFunctionTypeMismatch(Data, Function, calleeRTTI, fnRTTI, Opts)) 201 1.1 mrg Die(); 202 1.1 mrg } 203 1.1 mrg } // namespace __ubsan 204 1.1 mrg 205 1.1 mrg #endif // CAN_SANITIZE_UB 206