コード例 #1
0
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));
      }
    }
  }
}
コード例 #2
0
/*
 * 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;
}
コード例 #3
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);
}
コード例 #4
0
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;
    }
  }
}
コード例 #5
0
ファイル: cacheflush.cpp プロジェクト: MIPS/bionic
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;
}
コード例 #6
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;
}
コード例 #7
0
ファイル: syslog.cpp プロジェクト: MIPS/bionic
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);
}
コード例 #8
0
// 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);
}
コード例 #9
0
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;
}
コード例 #10
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);
}