1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <inttypes.h>
30 #include <stdint.h>
31
32 #include <array>
33 #include <mutex>
34 #include <string>
35 #include <string_view>
36 #include <thread>
37 #include <utility>
38 #include <vector>
39
40 #include <android/fdsan.h>
41 #include <android/set_abort_message.h>
42 #include <bionic/fdtrack.h>
43
44 #include <android-base/no_destructor.h>
45 #include <android-base/thread_annotations.h>
46 #include <async_safe/log.h>
47 #include <bionic/reserved_signals.h>
48 #include <unwindstack/Maps.h>
49 #include <unwindstack/Regs.h>
50 #include <unwindstack/RegsGetLocal.h>
51 #include <unwindstack/Unwinder.h>
52
53 struct FdEntry {
54 std::mutex mutex;
55 std::vector<unwindstack::FrameData> backtrace GUARDED_BY(mutex);
56 };
57
58 extern "C" void fdtrack_dump();
59 extern "C" void fdtrack_dump_fatal();
60
61 using fdtrack_callback_t = bool (*)(int fd, const char* const* function_names,
62 const uint64_t* function_offsets, size_t count, void* arg);
63 extern "C" void fdtrack_iterate(fdtrack_callback_t callback, void* arg);
64
65 static void fd_hook(android_fdtrack_event* event);
66
67 // Backtraces for the first 4k file descriptors ought to be enough to diagnose an fd leak.
68 static constexpr size_t kFdTableSize = 4096;
69
70 // Only unwind up to 32 frames outside of libfdtrack.so.
71 static constexpr size_t kStackDepth = 32;
72
73 // Skip any initial frames from libfdtrack.so.
74 // Also ignore frames from ART (http://b/236197847) because we'd rather spend
75 // our precious few frames on the actual Java calling code rather than the
76 // implementation of JNI!
77 static std::vector<std::string> kSkipFdtrackLib
78 [[clang::no_destroy]] = {"libfdtrack.so", "libart.so"};
79
80 static bool installed = false;
81 static std::array<FdEntry, kFdTableSize> stack_traces [[clang::no_destroy]];
Maps()82 static unwindstack::LocalUpdatableMaps& Maps() {
83 static android::base::NoDestructor<unwindstack::LocalUpdatableMaps> maps;
84 return *maps.get();
85 }
ProcessMemory()86 static std::shared_ptr<unwindstack::Memory>& ProcessMemory() {
87 static android::base::NoDestructor<std::shared_ptr<unwindstack::Memory>> process_memory;
88 return *process_memory.get();
89 }
90
ctor()91 __attribute__((constructor)) static void ctor() {
92 for (auto& entry : stack_traces) {
93 entry.backtrace.reserve(kStackDepth);
94 }
95
96 struct sigaction sa = {};
97 sa.sa_sigaction = [](int, siginfo_t* siginfo, void*) {
98 if (siginfo->si_code == SI_QUEUE && siginfo->si_int == 1) {
99 fdtrack_dump_fatal();
100 } else {
101 fdtrack_dump();
102 }
103 };
104 sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
105 sigaction(BIONIC_SIGNAL_FDTRACK, &sa, nullptr);
106
107 if (Maps().Parse()) {
108 ProcessMemory() = unwindstack::Memory::CreateProcessMemoryThreadCached(getpid());
109 android_fdtrack_hook_t expected = nullptr;
110 installed = android_fdtrack_compare_exchange_hook(&expected, &fd_hook);
111 }
112
113 android_fdtrack_set_globally_enabled(true);
114 }
115
dtor()116 __attribute__((destructor)) static void dtor() {
117 if (installed) {
118 android_fdtrack_hook_t expected = &fd_hook;
119 android_fdtrack_compare_exchange_hook(&expected, nullptr);
120 }
121 }
122
GetFdEntry(int fd)123 FdEntry* GetFdEntry(int fd) {
124 if (fd >= 0 && fd < static_cast<int>(kFdTableSize)) {
125 return &stack_traces[fd];
126 }
127 return nullptr;
128 }
129
fd_hook(android_fdtrack_event * event)130 static void fd_hook(android_fdtrack_event* event) {
131 if (event->type == ANDROID_FDTRACK_EVENT_TYPE_CREATE) {
132 if (FdEntry* entry = GetFdEntry(event->fd); entry) {
133 std::lock_guard<std::mutex> lock(entry->mutex);
134 entry->backtrace.clear();
135
136 std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
137 unwindstack::RegsGetLocal(regs.get());
138 unwindstack::Unwinder unwinder(kStackDepth, &Maps(), regs.get(), ProcessMemory());
139 unwinder.Unwind(&kSkipFdtrackLib);
140 entry->backtrace = unwinder.ConsumeFrames();
141 }
142 } else if (event->type == ANDROID_FDTRACK_EVENT_TYPE_CLOSE) {
143 if (FdEntry* entry = GetFdEntry(event->fd); entry) {
144 std::lock_guard<std::mutex> lock(entry->mutex);
145 entry->backtrace.clear();
146 }
147 }
148 }
149
fdtrack_iterate(fdtrack_callback_t callback,void * arg)150 void fdtrack_iterate(fdtrack_callback_t callback, void* arg) {
151 bool prev = android_fdtrack_set_enabled(false);
152
153 for (int fd = 0; fd < static_cast<int>(stack_traces.size()); ++fd) {
154 const char* function_names[kStackDepth];
155 uint64_t function_offsets[kStackDepth];
156 FdEntry* entry = GetFdEntry(fd);
157 if (!entry) {
158 continue;
159 }
160
161 if (!entry->mutex.try_lock()) {
162 async_safe_format_log(ANDROID_LOG_WARN, "fdtrack", "fd %d locked, skipping", fd);
163 continue;
164 }
165
166 if (entry->backtrace.empty()) {
167 entry->mutex.unlock();
168 continue;
169 } else if (entry->backtrace.size() < 2) {
170 async_safe_format_log(ANDROID_LOG_WARN, "fdtrack", "fd %d missing frames: size = %zu", fd,
171 entry->backtrace.size());
172
173 entry->mutex.unlock();
174 continue;
175 }
176
177 for (size_t i = 0; i < entry->backtrace.size(); ++i) {
178 function_names[i] = entry->backtrace[i].function_name.c_str();
179 function_offsets[i] = entry->backtrace[i].function_offset;
180 }
181
182 bool should_continue =
183 callback(fd, function_names, function_offsets, entry->backtrace.size(), arg);
184
185 entry->mutex.unlock();
186
187 if (!should_continue) {
188 break;
189 }
190 }
191
192 android_fdtrack_set_enabled(prev);
193 }
194
hash_stack(const char * const * function_names,const uint64_t * function_offsets,size_t stack_depth)195 static size_t hash_stack(const char* const* function_names, const uint64_t* function_offsets,
196 size_t stack_depth) {
197 size_t hash = 0;
198 for (size_t i = 0; i < stack_depth; ++i) {
199 // To future maintainers: if a libc++ update ever makes this invalid, replace this with +.
200 hash = std::__hash_combine(hash, std::hash<std::string_view>()(function_names[i]));
201 hash = std::__hash_combine(hash, std::hash<uint64_t>()(function_offsets[i]));
202 }
203 return hash;
204 }
205
fdtrack_dump_impl(bool fatal)206 static void fdtrack_dump_impl(bool fatal) {
207 if (!installed) {
208 async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fdtrack not installed");
209 } else {
210 async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fdtrack dumping...");
211 }
212
213 // If we're aborting, identify the most common stack in the hopes that it's the culprit,
214 // and emit that in the abort message so crash reporting can separate different fd leaks out.
215 // This is horrible and quadratic, but we need to avoid allocation since this can happen in
216 // response to a signal generated asynchronously. We're only going to dump 1k fds by default,
217 // and we're about to blow up the entire system, so this isn't too expensive.
218 struct StackInfo {
219 size_t hash = 0;
220 size_t count = 0;
221
222 size_t stack_depth = 0;
223 const char* function_names[kStackDepth];
224 uint64_t function_offsets[kStackDepth];
225 };
226 struct StackList {
227 size_t count = 0;
228 std::array<StackInfo, 128> data;
229 };
230 static StackList stacks;
231
232 fdtrack_iterate(
233 [](int fd, const char* const* function_names, const uint64_t* function_offsets,
234 size_t stack_depth, void* stacks_ptr) {
235 auto stacks = static_cast<StackList*>(stacks_ptr);
236 uint64_t fdsan_owner = android_fdsan_get_owner_tag(fd);
237 if (fdsan_owner != 0) {
238 async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fd %d: (owner = 0x%" PRIx64 ")", fd,
239 fdsan_owner);
240 } else {
241 async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fd %d: (unowned)", fd);
242 }
243
244 for (size_t i = 0; i < stack_depth; ++i) {
245 async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", " %zu: %s+%" PRIu64, i,
246 function_names[i], function_offsets[i]);
247 }
248
249 if (stacks) {
250 size_t hash = hash_stack(function_names, function_offsets, stack_depth);
251 bool found_stack = false;
252 for (size_t i = 0; i < stacks->count; ++i) {
253 if (stacks->data[i].hash == hash) {
254 ++stacks->data[i].count;
255 found_stack = true;
256 break;
257 }
258 }
259
260 if (!found_stack) {
261 if (stacks->count < stacks->data.size()) {
262 auto& stack = stacks->data[stacks->count++];
263 stack.hash = hash;
264 stack.count = 1;
265 stack.stack_depth = stack_depth;
266 for (size_t i = 0; i < stack_depth; ++i) {
267 stack.function_names[i] = function_names[i];
268 stack.function_offsets[i] = function_offsets[i];
269 }
270 }
271 }
272 }
273
274 return true;
275 },
276 fatal ? &stacks : nullptr);
277
278 if (fatal) {
279 // Find the most common stack.
280 size_t max = 0;
281 StackInfo* stack = nullptr;
282 for (size_t i = 0; i < stacks.count; ++i) {
283 if (stacks.data[i].count > max) {
284 stack = &stacks.data[i];
285 max = stack->count;
286 }
287 }
288
289 static char buf[1024];
290
291 if (!stack) {
292 async_safe_format_buffer(buf, sizeof(buf),
293 "aborting due to fd leak: failed to find most common stack");
294 } else {
295 char* p = buf;
296 p += async_safe_format_buffer(buf, sizeof(buf),
297 "aborting due to fd leak: most common stack =\n");
298
299 for (size_t i = 0; i < stack->stack_depth; ++i) {
300 ssize_t bytes_left = buf + sizeof(buf) - p;
301 if (bytes_left > 0) {
302 p += async_safe_format_buffer(p, buf + sizeof(buf) - p, " %zu: %s+%" PRIu64 "\n", i,
303 stack->function_names[i], stack->function_offsets[i]);
304 }
305 }
306 }
307
308 android_set_abort_message(buf);
309
310 // Abort on a different thread to avoid ART dumping runtime stacks.
311 std::thread([]() { abort(); }).join();
312 }
313 }
314
fdtrack_dump()315 void fdtrack_dump() {
316 fdtrack_dump_impl(false);
317 }
318
fdtrack_dump_fatal()319 void fdtrack_dump_fatal() {
320 fdtrack_dump_impl(true);
321 }
322