1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "libdebuggerd/scudo.h" 18 #include "libdebuggerd/tombstone.h" 19 20 #include "unwindstack/Memory.h" 21 #include "unwindstack/Unwinder.h" 22 23 #include <android-base/macros.h> 24 #include <bionic/macros.h> 25 26 #include "tombstone.pb.h" 27 28 std::unique_ptr<char[]> AllocAndReadFully(unwindstack::Memory* process_memory, uint64_t addr, 29 size_t size) { 30 auto buf = std::make_unique<char[]>(size); 31 if (!process_memory->ReadFully(addr, buf.get(), size)) { 32 return std::unique_ptr<char[]>(); 33 } 34 return buf; 35 } 36 37 ScudoCrashData::ScudoCrashData(unwindstack::Memory* process_memory, 38 const ProcessInfo& process_info) { 39 if (!process_info.has_fault_address) { 40 return; 41 } 42 43 auto stack_depot = AllocAndReadFully(process_memory, process_info.scudo_stack_depot, 44 __scudo_get_stack_depot_size()); 45 auto region_info = AllocAndReadFully(process_memory, process_info.scudo_region_info, 46 __scudo_get_region_info_size()); 47 auto ring_buffer = AllocAndReadFully(process_memory, process_info.scudo_ring_buffer, 48 __scudo_get_ring_buffer_size()); 49 50 untagged_fault_addr_ = process_info.untagged_fault_address; 51 uintptr_t fault_page = untagged_fault_addr_ & ~(PAGE_SIZE - 1); 52 53 uintptr_t memory_begin = fault_page - PAGE_SIZE * 16; 54 if (memory_begin > fault_page) { 55 return; 56 } 57 58 uintptr_t memory_end = fault_page + PAGE_SIZE * 16; 59 if (memory_end < fault_page) { 60 return; 61 } 62 63 auto memory = std::make_unique<char[]>(memory_end - memory_begin); 64 for (auto i = memory_begin; i != memory_end; i += PAGE_SIZE) { 65 process_memory->ReadFully(i, memory.get() + i - memory_begin, PAGE_SIZE); 66 } 67 68 auto memory_tags = std::make_unique<char[]>((memory_end - memory_begin) / kTagGranuleSize); 69 for (auto i = memory_begin; i != memory_end; i += kTagGranuleSize) { 70 memory_tags[(i - memory_begin) / kTagGranuleSize] = process_memory->ReadTag(i); 71 } 72 73 __scudo_get_error_info(&error_info_, process_info.maybe_tagged_fault_address, stack_depot.get(), 74 region_info.get(), ring_buffer.get(), memory.get(), memory_tags.get(), 75 memory_begin, memory_end - memory_begin); 76 } 77 78 bool ScudoCrashData::CrashIsMine() const { 79 return error_info_.reports[0].error_type != UNKNOWN; 80 } 81 82 void ScudoCrashData::FillInCause(Cause* cause, const scudo_error_report* report, 83 unwindstack::Unwinder* unwinder) const { 84 MemoryError* memory_error = cause->mutable_memory_error(); 85 HeapObject* heap_object = memory_error->mutable_heap(); 86 87 memory_error->set_tool(MemoryError_Tool_SCUDO); 88 switch (report->error_type) { 89 case USE_AFTER_FREE: 90 memory_error->set_type(MemoryError_Type_USE_AFTER_FREE); 91 break; 92 case BUFFER_OVERFLOW: 93 memory_error->set_type(MemoryError_Type_BUFFER_OVERFLOW); 94 break; 95 case BUFFER_UNDERFLOW: 96 memory_error->set_type(MemoryError_Type_BUFFER_UNDERFLOW); 97 break; 98 default: 99 memory_error->set_type(MemoryError_Type_UNKNOWN); 100 break; 101 } 102 103 heap_object->set_address(report->allocation_address); 104 heap_object->set_size(report->allocation_size); 105 unwinder->SetDisplayBuildID(true); 106 107 heap_object->set_allocation_tid(report->allocation_tid); 108 for (size_t i = 0; i < arraysize(report->allocation_trace) && report->allocation_trace[i]; ++i) { 109 unwindstack::FrameData frame_data = unwinder->BuildFrameFromPcOnly(report->allocation_trace[i]); 110 BacktraceFrame* f = heap_object->add_allocation_backtrace(); 111 fill_in_backtrace_frame(f, frame_data, unwinder->GetMaps()); 112 } 113 114 heap_object->set_deallocation_tid(report->deallocation_tid); 115 for (size_t i = 0; i < arraysize(report->deallocation_trace) && report->deallocation_trace[i]; 116 ++i) { 117 unwindstack::FrameData frame_data = 118 unwinder->BuildFrameFromPcOnly(report->deallocation_trace[i]); 119 BacktraceFrame* f = heap_object->add_deallocation_backtrace(); 120 fill_in_backtrace_frame(f, frame_data, unwinder->GetMaps()); 121 } 122 123 set_human_readable_cause(cause, untagged_fault_addr_); 124 } 125 126 void ScudoCrashData::AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinder* unwinder) const { 127 size_t report_num = 0; 128 while (report_num < sizeof(error_info_.reports) / sizeof(error_info_.reports[0]) && 129 error_info_.reports[report_num].error_type != UNKNOWN) { 130 FillInCause(tombstone->add_causes(), &error_info_.reports[report_num++], unwinder); 131 } 132 } 133 134 void ScudoCrashData::DumpCause(log_t* log, unwindstack::Unwinder* unwinder) const { 135 if (error_info_.reports[1].error_type != UNKNOWN) { 136 _LOG(log, logtype::HEADER, 137 "\nNote: multiple potential causes for this crash were detected, listing them in " 138 "decreasing order of probability.\n"); 139 } 140 141 size_t report_num = 0; 142 while (report_num < sizeof(error_info_.reports) / sizeof(error_info_.reports[0]) && 143 error_info_.reports[report_num].error_type != UNKNOWN) { 144 DumpReport(&error_info_.reports[report_num++], log, unwinder); 145 } 146 } 147 148 void ScudoCrashData::DumpReport(const scudo_error_report* report, log_t* log, 149 unwindstack::Unwinder* unwinder) const { 150 const char *error_type_str; 151 switch (report->error_type) { 152 case USE_AFTER_FREE: 153 error_type_str = "Use After Free"; 154 break; 155 case BUFFER_OVERFLOW: 156 error_type_str = "Buffer Overflow"; 157 break; 158 case BUFFER_UNDERFLOW: 159 error_type_str = "Buffer Underflow"; 160 break; 161 default: 162 error_type_str = "Unknown"; 163 break; 164 } 165 166 uintptr_t diff; 167 const char* location_str; 168 169 if (untagged_fault_addr_ < report->allocation_address) { 170 // Buffer Underflow, 6 bytes left of a 41-byte allocation at 0xdeadbeef. 171 location_str = "left of"; 172 diff = report->allocation_address - untagged_fault_addr_; 173 } else if (untagged_fault_addr_ - report->allocation_address < report->allocation_size) { 174 // Use After Free, 40 bytes into a 41-byte allocation at 0xdeadbeef. 175 location_str = "into"; 176 diff = untagged_fault_addr_ - report->allocation_address; 177 } else { 178 // Buffer Overflow, 6 bytes right of a 41-byte allocation at 0xdeadbeef. 179 location_str = "right of"; 180 diff = untagged_fault_addr_ - report->allocation_address - report->allocation_size; 181 } 182 183 // Suffix of 'bytes', i.e. 4 bytes' vs. '1 byte'. 184 const char* byte_suffix = "s"; 185 if (diff == 1) { 186 byte_suffix = ""; 187 } 188 _LOG(log, logtype::HEADER, 189 "\nCause: [MTE]: %s, %" PRIuPTR " byte%s %s a %zu-byte allocation at 0x%" PRIxPTR "\n", 190 error_type_str, diff, byte_suffix, location_str, report->allocation_size, 191 report->allocation_address); 192 193 if (report->allocation_trace[0]) { 194 _LOG(log, logtype::BACKTRACE, "\nallocated by thread %u:\n", report->allocation_tid); 195 unwinder->SetDisplayBuildID(true); 196 for (size_t i = 0; i < arraysize(report->allocation_trace) && report->allocation_trace[i]; 197 ++i) { 198 unwindstack::FrameData frame_data = 199 unwinder->BuildFrameFromPcOnly(report->allocation_trace[i]); 200 frame_data.num = i; 201 _LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str()); 202 } 203 } 204 205 if (report->deallocation_trace[0]) { 206 _LOG(log, logtype::BACKTRACE, "\ndeallocated by thread %u:\n", report->deallocation_tid); 207 unwinder->SetDisplayBuildID(true); 208 for (size_t i = 0; i < arraysize(report->deallocation_trace) && report->deallocation_trace[i]; 209 ++i) { 210 unwindstack::FrameData frame_data = 211 unwinder->BuildFrameFromPcOnly(report->deallocation_trace[i]); 212 frame_data.num = i; 213 _LOG(log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(frame_data).c_str()); 214 } 215 } 216 } 217