• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 <dirent.h>
30 #include <fcntl.h>
31 #include <poll.h>
32 #include <pthread.h>
33 #include <stddef.h>
34 #include <sys/ucontext.h>
35 #include <syscall.h>
36 #include <unistd.h>
37 
38 #include <atomic>
39 #include <memory>
40 #include <mutex>
41 
42 #include <android-base/file.h>
43 #include <android-base/unique_fd.h>
44 #include <async_safe/log.h>
45 #include <backtrace/BacktraceMap.h>
46 #include <unwindstack/Memory.h>
47 #include <unwindstack/Regs.h>
48 
49 #include "debuggerd/handler.h"
50 #include "tombstoned/tombstoned.h"
51 #include "util.h"
52 
53 #include "libdebuggerd/backtrace.h"
54 #include "libdebuggerd/tombstone.h"
55 
56 using android::base::unique_fd;
57 using unwindstack::Regs;
58 
59 extern "C" bool __linker_enable_fallback_allocator();
60 extern "C" void __linker_disable_fallback_allocator();
61 
62 // This is incredibly sketchy to do inside of a signal handler, especially when libbacktrace
63 // uses the C++ standard library throughout, but this code runs in the linker, so we'll be using
64 // the linker's malloc instead of the libc one. Switch it out for a replacement, just in case.
65 //
66 // This isn't the default method of dumping because it can fail in cases such as address space
67 // exhaustion.
debuggerd_fallback_trace(int output_fd,ucontext_t * ucontext)68 static void debuggerd_fallback_trace(int output_fd, ucontext_t* ucontext) {
69   if (!__linker_enable_fallback_allocator()) {
70     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "fallback allocator already in use");
71     return;
72   }
73 
74   {
75     std::unique_ptr<Regs> regs;
76 
77     ThreadInfo thread;
78     thread.pid = getpid();
79     thread.tid = gettid();
80     thread.thread_name = get_thread_name(gettid());
81     thread.registers.reset(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext));
82 
83     // TODO: Create this once and store it in a global?
84     std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid()));
85     dump_backtrace_thread(output_fd, map.get(), thread);
86   }
87   __linker_disable_fallback_allocator();
88 }
89 
debuggerd_fallback_tombstone(int output_fd,ucontext_t * ucontext,siginfo_t * siginfo,void * abort_message)90 static void debuggerd_fallback_tombstone(int output_fd, ucontext_t* ucontext, siginfo_t* siginfo,
91                                          void* abort_message) {
92   if (!__linker_enable_fallback_allocator()) {
93     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "fallback allocator already in use");
94     return;
95   }
96 
97   engrave_tombstone_ucontext(output_fd, reinterpret_cast<uintptr_t>(abort_message), siginfo,
98                              ucontext);
99   __linker_disable_fallback_allocator();
100 }
101 
iterate_siblings(bool (* callback)(pid_t,int),int output_fd)102 static void iterate_siblings(bool (*callback)(pid_t, int), int output_fd) {
103   pid_t current_tid = gettid();
104   char buf[BUFSIZ];
105   snprintf(buf, sizeof(buf), "/proc/%d/task", current_tid);
106   DIR* dir = opendir(buf);
107 
108   if (!dir) {
109     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to open %s: %s", buf, strerror(errno));
110     return;
111   }
112 
113   struct dirent* ent;
114   while ((ent = readdir(dir))) {
115     char* end;
116     long tid = strtol(ent->d_name, &end, 10);
117     if (end == ent->d_name || *end != '\0') {
118       continue;
119     }
120 
121     if (tid != current_tid) {
122       callback(tid, output_fd);
123     }
124   }
125   closedir(dir);
126 }
127 
forward_output(int src_fd,int dst_fd,pid_t expected_tid)128 static bool forward_output(int src_fd, int dst_fd, pid_t expected_tid) {
129   // Make sure the thread actually got the signal.
130   struct pollfd pfd = {
131     .fd = src_fd, .events = POLLIN,
132   };
133 
134   // Wait for up to a second for output to start flowing.
135   if (poll(&pfd, 1, 1000) != 1) {
136     return false;
137   }
138 
139   pid_t tid;
140   if (TEMP_FAILURE_RETRY(read(src_fd, &tid, sizeof(tid))) != sizeof(tid)) {
141     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to read tid");
142     return false;
143   }
144 
145   if (tid != expected_tid) {
146     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "received tid %d, expected %d", tid,
147                           expected_tid);
148     return false;
149   }
150 
151   while (true) {
152     char buf[512];
153     ssize_t rc = TEMP_FAILURE_RETRY(read(src_fd, buf, sizeof(buf)));
154     if (rc == 0) {
155       return true;
156     } else if (rc < 0) {
157       return false;
158     }
159 
160     if (!android::base::WriteFully(dst_fd, buf, rc)) {
161       // We failed to write to tombstoned, but there's not much we can do.
162       // Keep reading from src_fd to keep things going.
163       continue;
164     }
165   }
166 }
167 
168 struct __attribute__((__packed__)) packed_thread_output {
169   int32_t tid;
170   int32_t fd;
171 };
172 
pack_thread_fd(pid_t tid,int fd)173 static uint64_t pack_thread_fd(pid_t tid, int fd) {
174   packed_thread_output packed = {.tid = tid, .fd = fd};
175   uint64_t result;
176   static_assert(sizeof(packed) == sizeof(result));
177   memcpy(&result, &packed, sizeof(packed));
178   return result;
179 }
180 
unpack_thread_fd(uint64_t value)181 static std::pair<pid_t, int> unpack_thread_fd(uint64_t value) {
182   packed_thread_output result;
183   memcpy(&result, &value, sizeof(value));
184   return std::make_pair(result.tid, result.fd);
185 }
186 
trace_handler(siginfo_t * info,ucontext_t * ucontext)187 static void trace_handler(siginfo_t* info, ucontext_t* ucontext) {
188   static std::atomic<uint64_t> trace_output(pack_thread_fd(-1, -1));
189 
190   if (info->si_value.sival_int == ~0) {
191     // Asked to dump by the original signal recipient.
192     uint64_t val = trace_output.load();
193     auto [tid, fd] = unpack_thread_fd(val);
194     if (tid != gettid()) {
195       // We received some other thread's info request?
196       async_safe_format_log(ANDROID_LOG_ERROR, "libc",
197                             "thread %d received output fd for thread %d?", gettid(), tid);
198       return;
199     }
200 
201     if (!trace_output.compare_exchange_strong(val, pack_thread_fd(-1, -1))) {
202       // Presumably, the timeout in forward_output expired, and the main thread moved on.
203       // If this happened, the main thread closed our fd for us, so just return.
204       async_safe_format_log(ANDROID_LOG_ERROR, "libc", "cmpxchg for thread %d failed", gettid());
205       return;
206     }
207 
208     // Write our tid to the output fd to let the main thread know that we're working.
209     if (TEMP_FAILURE_RETRY(write(fd, &tid, sizeof(tid))) == sizeof(tid)) {
210       debuggerd_fallback_trace(fd, ucontext);
211     } else {
212       async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to write to output fd");
213     }
214 
215     close(fd);
216     return;
217   }
218 
219   // Only allow one thread to perform a trace at a time.
220   static pthread_mutex_t trace_mutex = PTHREAD_MUTEX_INITIALIZER;
221   int ret = pthread_mutex_trylock(&trace_mutex);
222   if (ret != 0) {
223     async_safe_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_try_lock failed: %s",
224                           strerror(ret));
225     return;
226   }
227 
228   // Fetch output fd from tombstoned.
229   unique_fd tombstone_socket, output_fd;
230   if (!tombstoned_connect(getpid(), &tombstone_socket, &output_fd, kDebuggerdNativeBacktrace)) {
231     goto exit;
232   }
233 
234   dump_backtrace_header(output_fd.get());
235 
236   // Dump our own stack.
237   debuggerd_fallback_trace(output_fd.get(), ucontext);
238 
239   // Send a signal to all of our siblings, asking them to dump their stack.
240   iterate_siblings(
241       [](pid_t tid, int output_fd) {
242         // Use a pipe, to be able to detect situations where the thread gracefully exits before
243         // receiving our signal.
244         unique_fd pipe_read, pipe_write;
245         if (!Pipe(&pipe_read, &pipe_write)) {
246           async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to create pipe: %s",
247                                 strerror(errno));
248           return false;
249         }
250 
251         uint64_t expected = pack_thread_fd(-1, -1);
252         if (!trace_output.compare_exchange_strong(expected,
253                                                   pack_thread_fd(tid, pipe_write.release()))) {
254           auto [tid, fd] = unpack_thread_fd(expected);
255           async_safe_format_log(ANDROID_LOG_ERROR, "libc",
256                                 "thread %d is already outputting to fd %d?", tid, fd);
257           return false;
258         }
259 
260         siginfo_t siginfo = {};
261         siginfo.si_code = SI_QUEUE;
262         siginfo.si_value.sival_int = ~0;
263         siginfo.si_pid = getpid();
264         siginfo.si_uid = getuid();
265 
266         if (syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, DEBUGGER_SIGNAL, &siginfo) != 0) {
267           async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to send trace signal to %d: %s",
268                                 tid, strerror(errno));
269           return false;
270         }
271 
272         bool success = forward_output(pipe_read.get(), output_fd, tid);
273         if (!success) {
274           async_safe_format_log(ANDROID_LOG_ERROR, "libc",
275                                 "timeout expired while waiting for thread %d to dump", tid);
276         }
277 
278         // Regardless of whether the poll succeeds, check to see if the thread took fd ownership.
279         uint64_t post_wait = trace_output.exchange(pack_thread_fd(-1, -1));
280         if (post_wait != pack_thread_fd(-1, -1)) {
281           auto [tid, fd] = unpack_thread_fd(post_wait);
282           if (fd != -1) {
283             async_safe_format_log(ANDROID_LOG_ERROR, "libc", "closing fd %d for thread %d", fd, tid);
284             close(fd);
285           }
286         }
287 
288         return true;
289       },
290       output_fd.get());
291 
292   dump_backtrace_footer(output_fd.get());
293   tombstoned_notify_completion(tombstone_socket.get());
294 
295 exit:
296   pthread_mutex_unlock(&trace_mutex);
297 }
298 
crash_handler(siginfo_t * info,ucontext_t * ucontext,void * abort_message)299 static void crash_handler(siginfo_t* info, ucontext_t* ucontext, void* abort_message) {
300   // Only allow one thread to handle a crash at a time (this can happen multiple times without
301   // exit, since tombstones can be requested without a real crash happening.)
302   static std::recursive_mutex crash_mutex;
303   static int lock_count;
304 
305   crash_mutex.lock();
306   if (lock_count++ > 0) {
307     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "recursed signal handler call, exiting");
308     _exit(1);
309   }
310 
311   unique_fd tombstone_socket, output_fd;
312   bool tombstoned_connected =
313       tombstoned_connect(getpid(), &tombstone_socket, &output_fd, kDebuggerdTombstone);
314   debuggerd_fallback_tombstone(output_fd.get(), ucontext, info, abort_message);
315   if (tombstoned_connected) {
316     tombstoned_notify_completion(tombstone_socket.get());
317   }
318 
319   --lock_count;
320   crash_mutex.unlock();
321 }
322 
debuggerd_fallback_handler(siginfo_t * info,ucontext_t * ucontext,void * abort_message)323 extern "C" void debuggerd_fallback_handler(siginfo_t* info, ucontext_t* ucontext,
324                                            void* abort_message) {
325   if (info->si_signo == DEBUGGER_SIGNAL && info->si_value.sival_int != 0) {
326     return trace_handler(info, ucontext);
327   } else {
328     return crash_handler(info, ucontext, abort_message);
329   }
330 }
331