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/gwp_asan.h"
19 
20 #include "unwindstack/Memory.h"
21 #include "unwindstack/Unwinder.h"
22 
23 #include <bionic/macros.h>
24 
AllocAndReadFully(unwindstack::Memory * process_memory,uint64_t addr,size_t size)25 std::unique_ptr<char[]> AllocAndReadFully(unwindstack::Memory* process_memory, uint64_t addr,
26                                           size_t size) {
27   auto buf = std::make_unique<char[]>(size);
28   if (!process_memory->ReadFully(addr, buf.get(), size)) {
29     return std::unique_ptr<char[]>();
30   }
31   return buf;
32 }
33 
34 static const uintptr_t kTagGranuleSize = 16;
35 
ScudoCrashData(unwindstack::Memory * process_memory,const ProcessInfo & process_info)36 ScudoCrashData::ScudoCrashData(unwindstack::Memory* process_memory,
37                                const ProcessInfo& process_info) {
38   if (!process_info.has_fault_address) {
39     return;
40   }
41 
42   auto stack_depot = AllocAndReadFully(process_memory, process_info.scudo_stack_depot,
43                                        __scudo_get_stack_depot_size());
44   auto region_info = AllocAndReadFully(process_memory, process_info.scudo_region_info,
45                                        __scudo_get_region_info_size());
46 
47   untagged_fault_addr_ = untag_address(process_info.fault_address);
48   uintptr_t fault_page = untagged_fault_addr_ & ~(PAGE_SIZE - 1);
49 
50   uintptr_t memory_begin = fault_page - PAGE_SIZE * 16;
51   if (memory_begin > fault_page) {
52     return;
53   }
54 
55   uintptr_t memory_end = fault_page + PAGE_SIZE * 16;
56   if (memory_end < fault_page) {
57     return;
58   }
59 
60   auto memory = std::make_unique<char[]>(memory_end - memory_begin);
61   for (auto i = memory_begin; i != memory_end; i += PAGE_SIZE) {
62     process_memory->ReadFully(i, memory.get() + i - memory_begin, PAGE_SIZE);
63   }
64 
65   auto memory_tags = std::make_unique<char[]>((memory_end - memory_begin) / kTagGranuleSize);
66   for (auto i = memory_begin; i != memory_end; i += kTagGranuleSize) {
67     memory_tags[(i - memory_begin) / kTagGranuleSize] = process_memory->ReadTag(i);
68   }
69 
70   __scudo_get_error_info(&error_info_, process_info.fault_address, stack_depot.get(),
71                          region_info.get(), memory.get(), memory_tags.get(), memory_begin,
72                          memory_end - memory_begin);
73 }
74 
CrashIsMine() const75 bool ScudoCrashData::CrashIsMine() const {
76   return error_info_.reports[0].error_type != UNKNOWN;
77 }
78 
DumpCause(log_t * log,unwindstack::Unwinder * unwinder) const79 void ScudoCrashData::DumpCause(log_t* log, unwindstack::Unwinder* unwinder) const {
80   if (error_info_.reports[1].error_type != UNKNOWN) {
81     _LOG(log, logtype::HEADER,
82          "\nNote: multiple potential causes for this crash were detected, listing them in "
83          "decreasing order of probability.\n");
84   }
85 
86   size_t report_num = 0;
87   while (report_num < sizeof(error_info_.reports) / sizeof(error_info_.reports[0]) &&
88          error_info_.reports[report_num].error_type != UNKNOWN) {
89     DumpReport(&error_info_.reports[report_num++], log, unwinder);
90   }
91 }
92 
DumpReport(const scudo_error_report * report,log_t * log,unwindstack::Unwinder * unwinder) const93 void ScudoCrashData::DumpReport(const scudo_error_report* report, log_t* log,
94                                 unwindstack::Unwinder* unwinder) const {
95   const char *error_type_str;
96   switch (report->error_type) {
97     case USE_AFTER_FREE:
98       error_type_str = "Use After Free";
99       break;
100     case BUFFER_OVERFLOW:
101       error_type_str = "Buffer Overflow";
102       break;
103     case BUFFER_UNDERFLOW:
104       error_type_str = "Buffer Underflow";
105       break;
106     default:
107       error_type_str = "Unknown";
108       break;
109   }
110 
111   uintptr_t diff;
112   const char* location_str;
113 
114   if (untagged_fault_addr_ < report->allocation_address) {
115     // Buffer Underflow, 6 bytes left of a 41-byte allocation at 0xdeadbeef.
116     location_str = "left of";
117     diff = report->allocation_address - untagged_fault_addr_;
118   } else if (untagged_fault_addr_ - report->allocation_address < report->allocation_size) {
119     // Use After Free, 40 bytes into a 41-byte allocation at 0xdeadbeef.
120     location_str = "into";
121     diff = untagged_fault_addr_ - report->allocation_address;
122   } else {
123     // Buffer Overflow, 6 bytes right of a 41-byte allocation at 0xdeadbeef.
124     location_str = "right of";
125     diff = untagged_fault_addr_ - report->allocation_address - report->allocation_size;
126   }
127 
128   // Suffix of 'bytes', i.e. 4 bytes' vs. '1 byte'.
129   const char* byte_suffix = "s";
130   if (diff == 1) {
131     byte_suffix = "";
132   }
133   _LOG(log, logtype::HEADER,
134        "\nCause: [MTE]: %s, %" PRIuPTR " byte%s %s a %zu-byte allocation at 0x%" PRIxPTR "\n",
135        error_type_str, diff, byte_suffix, location_str, report->allocation_size,
136        report->allocation_address);
137 
138   if (report->allocation_trace[0]) {
139     _LOG(log, logtype::BACKTRACE, "\nallocated by thread %u:\n", report->allocation_tid);
140     unwinder->SetDisplayBuildID(true);
141     for (size_t i = 0; i < 64 && report->allocation_trace[i]; ++i) {
142       unwindstack::FrameData frame_data =
143           unwinder->BuildFrameFromPcOnly(report->allocation_trace[i]);
144       frame_data.num = i;
145       _LOG(log, logtype::BACKTRACE, "    %s\n", unwinder->FormatFrame(frame_data).c_str());
146     }
147   }
148 
149   if (report->deallocation_trace[0]) {
150     _LOG(log, logtype::BACKTRACE, "\ndeallocated by thread %u:\n", report->deallocation_tid);
151     unwinder->SetDisplayBuildID(true);
152     for (size_t i = 0; i < 64 && report->deallocation_trace[i]; ++i) {
153       unwindstack::FrameData frame_data =
154           unwinder->BuildFrameFromPcOnly(report->deallocation_trace[i]);
155       frame_data.num = i;
156       _LOG(log, logtype::BACKTRACE, "    %s\n", unwinder->FormatFrame(frame_data).c_str());
157     }
158   }
159 }
160