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