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
52using android::base::unique_fd;
53
54extern "C" void __linker_enable_fallback_allocator();
55extern "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.
63static 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
69static 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
77static 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
103static 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
131static 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
203exit:
204  pthread_mutex_unlock(&trace_mutex);
205}
206
207static 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
224extern "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