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