static void raise_caps() { // Raise CapInh to match CapPrm, so that we can set the ambient bits. __user_cap_header_struct capheader; memset(&capheader, 0, sizeof(capheader)); capheader.version = _LINUX_CAPABILITY_VERSION_3; capheader.pid = 0; __user_cap_data_struct capdata[2]; if (capget(&capheader, &capdata[0]) == -1) { fatal_errno("capget failed"); } if (capdata[0].permitted != capdata[0].inheritable || capdata[1].permitted != capdata[1].inheritable) { capdata[0].inheritable = capdata[0].permitted; capdata[1].inheritable = capdata[1].permitted; if (capset(&capheader, &capdata[0]) == -1) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "capset failed: %s", strerror(errno)); } } // Set the ambient capability bits so that crash_dump gets all of our caps and can ptrace us. uint64_t capmask = capdata[0].inheritable; capmask |= static_cast<uint64_t>(capdata[1].inheritable) << 32; for (unsigned long i = 0; i < 64; ++i) { if (capmask & (1ULL << i)) { if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) != 0) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to raise ambient capability %lu: %s", i, strerror(errno)); } } } }
/* * Returns true if the handler for signal "signum" has SA_SIGINFO set. */ static bool have_siginfo(int signum) { struct sigaction old_action; if (sigaction(signum, nullptr, &old_action) < 0) { async_safe_format_log(ANDROID_LOG_WARN, "libc", "Failed testing for SA_SIGINFO: %s", strerror(errno)); return false; } return (old_action.sa_flags & SA_SIGINFO) != 0; }
const prop_info* SystemProperties::Find(const char* name) { if (!initialized_) { return nullptr; } prop_area* pa = contexts_->GetPropAreaForName(name); if (!pa) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name); return nullptr; } return pa->find(name); }
int SystemProperties::Read(const prop_info* pi, char* name, char* value) { while (true) { uint32_t serial = Serial(pi); // acquire semantics size_t len = SERIAL_VALUE_LEN(serial); memcpy(value, pi->value, len + 1); // TODO: Fix the synchronization scheme here. // There is no fully supported way to implement this kind // of synchronization in C++11, since the memcpy races with // updates to pi, and the data being accessed is not atomic. // The following fence is unintuitive, but would be the // correct one if memcpy used memory_order_relaxed atomic accesses. // In practice it seems unlikely that the generated code would // would be any different, so this should be OK. atomic_thread_fence(memory_order_acquire); if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) { if (name != nullptr) { size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX); if (namelen >= PROP_NAME_MAX) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "The property name length for \"%s\" is >= %d;" " please use __system_property_read_callback" " to read this property. (the name is truncated to \"%s\")", pi->name, PROP_NAME_MAX - 1, name); } } if (is_read_only(pi->name) && pi->is_long()) { async_safe_format_log( ANDROID_LOG_ERROR, "libc", "The property \"%s\" has a value with length %zu that is too large for" " __system_property_get()/__system_property_read(); use" " __system_property_read_callback() instead.", pi->name, strlen(pi->long_value())); } return len; } } }
int cacheflush(long start, long end, long /*flags*/) { if (end < start) { // It looks like this is really a MIPS-style cacheflush call. static bool warned = false; if (!warned) { async_safe_format_log(ANDROID_LOG_WARN, "libc", "cacheflush called with (start,len) instead of (start,end)"); warned = true; } end += start; } // Use the GCC builtin. This will generate inline synci instructions if available, // or call _flush_cache(start, len, BCACHE) directly. __builtin___clear_cache(reinterpret_cast<char*>(start), reinterpret_cast<char*>(end)); return 0; }
int SystemProperties::Add(const char* name, unsigned int namelen, const char* value, unsigned int valuelen) { if (valuelen >= PROP_VALUE_MAX && !is_read_only(name)) { return -1; } if (namelen < 1) { return -1; } if (!initialized_) { return -1; } prop_area* serial_pa = contexts_->GetSerialPropArea(); if (serial_pa == nullptr) { return -1; } prop_area* pa = contexts_->GetPropAreaForName(name); if (!pa) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name); return -1; } bool ret = pa->add(name, namelen, value, valuelen); if (!ret) { return -1; } // There is only a single mutator, but we want to make sure that // updates are visible to a reader waiting for the update. atomic_store_explicit(serial_pa->serial(), atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1, memory_order_release); __futex_wake(serial_pa->serial(), INT32_MAX); return 0; }
void vsyslog(int priority, const char* fmt, va_list args) { int caller_errno = errno; // Check whether we're supposed to be logging messages of this priority. if ((syslog_priority_mask & LOG_MASK(LOG_PRI(priority))) == 0) { return; } // What's our log tag? const char* log_tag = syslog_log_tag; if (log_tag == NULL) { log_tag = getprogname(); } // What's our Android log priority? priority &= LOG_PRIMASK; int android_log_priority; if (priority <= LOG_ERR) { android_log_priority = ANDROID_LOG_ERROR; } else if (priority == LOG_WARNING) { android_log_priority = ANDROID_LOG_WARN; } else if (priority <= LOG_INFO) { android_log_priority = ANDROID_LOG_INFO; } else { android_log_priority = ANDROID_LOG_DEBUG; } // glibc's printf family support %m directly, but our BSD-based one doesn't. // If the format string seems to contain "%m", rewrite it. const char* log_fmt = fmt; if (strstr(fmt, "%m") != NULL) { size_t dst_len = 1024; char* dst = reinterpret_cast<char*>(malloc(dst_len)); log_fmt = dst; const char* src = fmt; for (; dst_len > 0 && *src != '\0'; ++src) { if (*src == '%' && *(src + 1) == 'm') { // Expand %m. size_t n = strlcpy(dst, strerror(caller_errno), dst_len); if (n >= dst_len) { n = dst_len; } dst += n; dst_len -= n; ++src; } else if (*src == '%' && *(src + 1) == '%') { // We need to copy pairs of '%'s so the %m test works. if (dst_len <= 2) { break; } *dst++ = '%'; --dst_len; *dst++ = '%'; --dst_len; ++src; } else { *dst++ = *src; --dst_len; } } *dst = '\0'; } // We can't let async_safe_format_log do the formatting because it doesn't support // all the printf functionality. char log_line[1024]; vsnprintf(log_line, sizeof(log_line), log_fmt, args); if (log_fmt != fmt) { free(const_cast<char*>(log_fmt)); } async_safe_format_log(android_log_priority, log_tag, "%s", log_line); }
// Handler that does crash dumping by forking and doing the processing in the child. // Do this by ptracing the relevant thread, and then execing debuggerd to do the actual dump. static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* context) { // Make sure we don't change the value of errno, in case a signal comes in between the process // making a syscall and checking errno. ErrnoRestorer restorer; // It's possible somebody cleared the SA_SIGINFO flag, which would mean // our "info" arg holds an undefined value. if (!have_siginfo(signal_number)) { info = nullptr; } struct siginfo si = {}; if (!info) { memset(&si, 0, sizeof(si)); si.si_signo = signal_number; si.si_code = SI_USER; si.si_pid = __getpid(); si.si_uid = getuid(); info = &si; } else if (info->si_code >= 0 || info->si_code == SI_TKILL) { // rt_tgsigqueueinfo(2)'s documentation appears to be incorrect on kernels // that contain commit 66dd34a (3.9+). The manpage claims to only allow // negative si_code values that are not SI_TKILL, but 66dd34a changed the // check to allow all si_code values in calls coming from inside the house. } void* abort_message = nullptr; if (g_callbacks.get_abort_message) { abort_message = g_callbacks.get_abort_message(); } if (prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) == 1) { // This check might be racy if another thread sets NO_NEW_PRIVS, but this should be unlikely, // you can only set NO_NEW_PRIVS to 1, and the effect should be at worst a single missing // ANR trace. debuggerd_fallback_handler(info, static_cast<ucontext_t*>(context), abort_message); resend_signal(info, false); return; } // Only allow one thread to handle a signal at a time. int ret = pthread_mutex_lock(&crash_mutex); if (ret != 0) { async_safe_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_lock failed: %s", strerror(ret)); return; } log_signal_summary(signal_number, info); // If this was a fatal crash, populate si_value with the abort message address if possible. // Note that applications can set an abort message without aborting. if (abort_message && signal_number != DEBUGGER_SIGNAL) { info->si_value.sival_ptr = abort_message; } debugger_thread_info thread_info = { .crash_dump_started = false, .pseudothread_tid = -1, .crashing_tid = __gettid(), .signal_number = signal_number, .info = info }; // Set PR_SET_DUMPABLE to 1, so that crash_dump can ptrace us. int orig_dumpable = prctl(PR_GET_DUMPABLE); if (prctl(PR_SET_DUMPABLE, 1) != 0) { fatal_errno("failed to set dumpable"); } // Essentially pthread_create without CLONE_FILES (see debuggerd_dispatch_pseudothread). pid_t child_pid = clone(debuggerd_dispatch_pseudothread, pseudothread_stack, CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID, &thread_info, nullptr, nullptr, &thread_info.pseudothread_tid); if (child_pid == -1) { fatal_errno("failed to spawn debuggerd dispatch thread"); } // Wait for the child to start... futex_wait(&thread_info.pseudothread_tid, -1); // and then wait for it to finish. futex_wait(&thread_info.pseudothread_tid, child_pid); // Restore PR_SET_DUMPABLE to its original value. if (prctl(PR_SET_DUMPABLE, orig_dumpable) != 0) { fatal_errno("failed to restore dumpable"); } // Signals can either be fatal or nonfatal. // For fatal signals, crash_dump will PTRACE_CONT us with the signal we // crashed with, so that processes using waitpid on us will see that we // exited with the correct exit status (e.g. so that sh will report // "Segmentation fault" instead of "Killed"). For this to work, we need // to deregister our signal handler for that signal before continuing. if (signal_number != DEBUGGER_SIGNAL) { signal(signal_number, SIG_DFL); } resend_signal(info, thread_info.crash_dump_started); if (info->si_signo == DEBUGGER_SIGNAL) { // If the signal is fatal, don't unlock the mutex to prevent other crashing threads from // starting to dump right before our death. pthread_mutex_unlock(&crash_mutex); } } void debuggerd_init(debuggerd_callbacks_t* callbacks) { if (callbacks) { g_callbacks = *callbacks; } void* thread_stack_allocation = mmap(nullptr, PAGE_SIZE * 3, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if (thread_stack_allocation == MAP_FAILED) { fatal_errno("failed to allocate debuggerd thread stack"); } char* stack = static_cast<char*>(thread_stack_allocation) + PAGE_SIZE; if (mprotect(stack, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) { fatal_errno("failed to mprotect debuggerd thread stack"); } // Stack grows negatively, set it to the last byte in the page... stack = (stack + PAGE_SIZE - 1); // and align it. stack -= 15; pseudothread_stack = stack; struct sigaction action; memset(&action, 0, sizeof(action)); sigfillset(&action.sa_mask); action.sa_sigaction = debuggerd_signal_handler; action.sa_flags = SA_RESTART | SA_SIGINFO; // Use the alternate signal stack if available so we can catch stack overflows. action.sa_flags |= SA_ONSTACK; debuggerd_register_handlers(&action); }
static int debuggerd_dispatch_pseudothread(void* arg) { debugger_thread_info* thread_info = static_cast<debugger_thread_info*>(arg); for (int i = 0; i < 1024; ++i) { close(i); } int devnull = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)); // devnull will be 0. TEMP_FAILURE_RETRY(dup2(devnull, STDOUT_FILENO)); TEMP_FAILURE_RETRY(dup2(devnull, STDERR_FILENO)); int pipefds[2]; if (pipe(pipefds) != 0) { fatal_errno("failed to create pipe"); } // Don't use fork(2) to avoid calling pthread_atfork handlers. int forkpid = clone(nullptr, nullptr, 0, nullptr); if (forkpid == -1) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "failed to fork in debuggerd signal handler: %s", strerror(errno)); } else if (forkpid == 0) { TEMP_FAILURE_RETRY(dup2(pipefds[1], STDOUT_FILENO)); close(pipefds[0]); close(pipefds[1]); raise_caps(); char main_tid[10]; char pseudothread_tid[10]; char debuggerd_dump_type[10]; async_safe_format_buffer(main_tid, sizeof(main_tid), "%d", thread_info->crashing_tid); async_safe_format_buffer(pseudothread_tid, sizeof(pseudothread_tid), "%d", thread_info->pseudothread_tid); async_safe_format_buffer(debuggerd_dump_type, sizeof(debuggerd_dump_type), "%d", get_dump_type(thread_info)); execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, main_tid, pseudothread_tid, debuggerd_dump_type, nullptr); fatal_errno("exec failed"); } else { close(pipefds[1]); char buf[4]; ssize_t rc = TEMP_FAILURE_RETRY(read(pipefds[0], &buf, sizeof(buf))); if (rc == -1) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "read of IPC pipe failed: %s", strerror(errno)); } else if (rc == 0) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper failed to exec"); } else if (rc != 1) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "read of IPC pipe returned unexpected value: %zd", rc); } else { if (buf[0] != '\1') { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper reported failure"); } else { thread_info->crash_dump_started = true; } } close(pipefds[0]); // Don't leave a zombie child. int status; if (TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0)) == -1) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s", strerror(errno)); } else if (WIFSTOPPED(status) || WIFSIGNALED(status)) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper crashed or stopped"); thread_info->crash_dump_started = false; } } syscall(__NR_exit, 0); return 0; }
/* * Writes a summary of the signal to the log file. We do this so that, if * for some reason we're not able to contact debuggerd, there is still some * indication of the failure in the log. * * We could be here as a result of native heap corruption, or while a * mutex is being held, so we don't want to use any libc functions that * could allocate memory or hold a lock. */ static void log_signal_summary(int signum, const siginfo_t* info) { char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) { strcpy(thread_name, "<name unknown>"); } else { // short names are null terminated by prctl, but the man page // implies that 16 byte names are not. thread_name[MAX_TASK_NAME_LEN] = 0; } if (signum == DEBUGGER_SIGNAL) { async_safe_format_log(ANDROID_LOG_INFO, "libc", "Requested dump for tid %d (%s)", __gettid(), thread_name); return; } const char* signal_name = "???"; bool has_address = false; switch (signum) { case SIGABRT: signal_name = "SIGABRT"; break; case SIGBUS: signal_name = "SIGBUS"; has_address = true; break; case SIGFPE: signal_name = "SIGFPE"; has_address = true; break; case SIGILL: signal_name = "SIGILL"; has_address = true; break; case SIGSEGV: signal_name = "SIGSEGV"; has_address = true; break; #if defined(SIGSTKFLT) case SIGSTKFLT: signal_name = "SIGSTKFLT"; break; #endif case SIGSYS: signal_name = "SIGSYS"; break; case SIGTRAP: signal_name = "SIGTRAP"; break; } // "info" will be null if the siginfo_t information was not available. // Many signals don't have an address or a code. char code_desc[32]; // ", code -6" char addr_desc[32]; // ", fault addr 0x1234" addr_desc[0] = code_desc[0] = 0; if (info != nullptr) { async_safe_format_buffer(code_desc, sizeof(code_desc), ", code %d", info->si_code); if (has_address) { async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr); } } char main_thread_name[MAX_TASK_NAME_LEN + 1]; if (!get_main_thread_name(main_thread_name, sizeof(main_thread_name))) { strncpy(main_thread_name, "<unknown>", sizeof(main_thread_name)); } async_safe_format_log( ANDROID_LOG_FATAL, "libc", "Fatal signal %d (%s)%s%s in tid %d (%s), pid %d (%s)", signum, signal_name, code_desc, addr_desc, __gettid(), thread_name, __getpid(), main_thread_name); }