• 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 
40 #include <android-base/file.h>
41 #include <android-base/unique_fd.h>
42 
43 #include "debuggerd/handler.h"
44 #include "debuggerd/tombstoned.h"
45 #include "debuggerd/util.h"
46 
47 #include "backtrace.h"
48 #include "tombstone.h"
49 
50 #include "private/libc_logging.h"
51 
52 using android::base::unique_fd;
53 
54 extern "C" void __linker_enable_fallback_allocator();
55 extern "C" void __linker_disable_fallback_allocator();
56 
57 // This is incredibly sketchy to do inside of a signal handler, especially when libbacktrace
58 // uses the C++ standard library throughout, but this code runs in the linker, so we'll be using
59 // the linker's malloc instead of the libc one. Switch it out for a replacement, just in case.
60 //
61 // This isn't the default method of dumping because it can fail in cases such as address space
62 // exhaustion.
debuggerd_fallback_trace(int output_fd,ucontext_t * ucontext)63 static void debuggerd_fallback_trace(int output_fd, ucontext_t* ucontext) {
64   __linker_enable_fallback_allocator();
65   dump_backtrace_ucontext(output_fd, ucontext);
66   __linker_disable_fallback_allocator();
67 }
68 
debuggerd_fallback_tombstone(int output_fd,ucontext_t * ucontext,siginfo_t * siginfo,void * abort_message)69 static void debuggerd_fallback_tombstone(int output_fd, ucontext_t* ucontext, siginfo_t* siginfo,
70                                          void* abort_message) {
71   __linker_enable_fallback_allocator();
72   engrave_tombstone_ucontext(output_fd, reinterpret_cast<uintptr_t>(abort_message), siginfo,
73                              ucontext);
74   __linker_disable_fallback_allocator();
75 }
76 
iterate_siblings(bool (* callback)(pid_t,int),int output_fd)77 static void iterate_siblings(bool (*callback)(pid_t, int), int output_fd) {
78   pid_t current_tid = gettid();
79   char buf[BUFSIZ];
80   snprintf(buf, sizeof(buf), "/proc/%d/task", current_tid);
81   DIR* dir = opendir(buf);
82 
83   if (!dir) {
84     __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to open %s: %s", buf, strerror(errno));
85     return;
86   }
87 
88   struct dirent* ent;
89   while ((ent = readdir(dir))) {
90     char* end;
91     long tid = strtol(ent->d_name, &end, 10);
92     if (end == ent->d_name || *end != '\0') {
93       continue;
94     }
95 
96     if (tid != current_tid) {
97       callback(tid, output_fd);
98     }
99   }
100   closedir(dir);
101 }
102 
forward_output(int src_fd,int dst_fd)103 static bool forward_output(int src_fd, int dst_fd) {
104   // Make sure the thread actually got the signal.
105   struct pollfd pfd = {
106     .fd = src_fd, .events = POLLIN,
107   };
108 
109   // Wait for up to a second for output to start flowing.
110   if (poll(&pfd, 1, 1000) != 1) {
111     return false;
112   }
113 
114   while (true) {
115     char buf[512];
116     ssize_t rc = TEMP_FAILURE_RETRY(read(src_fd, buf, sizeof(buf)));
117     if (rc == 0) {
118       return true;
119     } else if (rc < 0) {
120       return false;
121     }
122 
123     if (!android::base::WriteFully(dst_fd, buf, rc)) {
124       // We failed to write to tombstoned, but there's not much we can do.
125       // Keep reading from src_fd to keep things going.
126       continue;
127     }
128   }
129 }
130 
trace_handler(siginfo_t * info,ucontext_t * ucontext)131 static void trace_handler(siginfo_t* info, ucontext_t* ucontext) {
132   static std::atomic<int> trace_output_fd(-1);
133 
134   if (info->si_value.sival_int == ~0) {
135     // Asked to dump by the original signal recipient.
136     debuggerd_fallback_trace(trace_output_fd, ucontext);
137 
138     int tmp = trace_output_fd.load();
139     trace_output_fd.store(-1);
140     close(tmp);
141     return;
142   }
143 
144   // Only allow one thread to perform a trace at a time.
145   static pthread_mutex_t trace_mutex = PTHREAD_MUTEX_INITIALIZER;
146   int ret = pthread_mutex_trylock(&trace_mutex);
147   if (ret != 0) {
148     __libc_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_try_lock failed: %s", strerror(ret));
149     return;
150   }
151 
152   // Fetch output fd from tombstoned.
153   unique_fd tombstone_socket, output_fd;
154   if (!tombstoned_connect(getpid(), &tombstone_socket, &output_fd)) {
155     goto exit;
156   }
157 
158   dump_backtrace_header(output_fd.get());
159 
160   // Dump our own stack.
161   debuggerd_fallback_trace(output_fd.get(), ucontext);
162 
163   // Send a signal to all of our siblings, asking them to dump their stack.
164   iterate_siblings(
165     [](pid_t tid, int output_fd) {
166       // Use a pipe, to be able to detect situations where the thread gracefully exits before
167       // receiving our signal.
168       unique_fd pipe_read, pipe_write;
169       if (!Pipe(&pipe_read, &pipe_write)) {
170         __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to create pipe: %s", strerror(errno));
171         return false;
172       }
173 
174       trace_output_fd.store(pipe_write.get());
175 
176       siginfo_t siginfo = {};
177       siginfo.si_code = SI_QUEUE;
178       siginfo.si_value.sival_int = ~0;
179       siginfo.si_pid = getpid();
180       siginfo.si_uid = getuid();
181 
182       if (syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, DEBUGGER_SIGNAL, &siginfo) != 0) {
183         __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to send trace signal to %d: %s", tid,
184                           strerror(errno));
185         return false;
186       }
187 
188       bool success = forward_output(pipe_read.get(), output_fd);
189       if (success) {
190         // The signaled thread has closed trace_output_fd already.
191         (void)pipe_write.release();
192       } else {
193         trace_output_fd.store(-1);
194       }
195 
196       return true;
197     },
198     output_fd.get());
199 
200   dump_backtrace_footer(output_fd.get());
201   tombstoned_notify_completion(tombstone_socket.get());
202 
203 exit:
204   pthread_mutex_unlock(&trace_mutex);
205 }
206 
crash_handler(siginfo_t * info,ucontext_t * ucontext,void * abort_message)207 static void crash_handler(siginfo_t* info, ucontext_t* ucontext, void* abort_message) {
208   // Only allow one thread to handle a crash.
209   static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
210   int ret = pthread_mutex_lock(&crash_mutex);
211   if (ret != 0) {
212     __libc_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_lock failed: %s", strerror(ret));
213     return;
214   }
215 
216   unique_fd tombstone_socket, output_fd;
217   bool tombstoned_connected = tombstoned_connect(getpid(), &tombstone_socket, &output_fd);
218   debuggerd_fallback_tombstone(output_fd.get(), ucontext, info, abort_message);
219   if (tombstoned_connected) {
220     tombstoned_notify_completion(tombstone_socket.get());
221   }
222 }
223 
debuggerd_fallback_handler(siginfo_t * info,ucontext_t * ucontext,void * abort_message)224 extern "C" void debuggerd_fallback_handler(siginfo_t* info, ucontext_t* ucontext,
225                                            void* abort_message) {
226   if (info->si_signo == DEBUGGER_SIGNAL) {
227     return trace_handler(info, ucontext);
228   } else {
229     return crash_handler(info, ucontext, abort_message);
230   }
231 }
232