Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b3ee52e4 authored by Josh Gao's avatar Josh Gao
Browse files

debuggerd_handler: don't use clone(..., SIGCHLD, ...)

Processes that handle SIGCHLD can race with the crash handler to wait
on the crash_dump process. Use clone flags that cause the forked
child's death to not be reported via SIGCHLD, and don't bail out of
dumping when waitpid returns ECHILD (in case another thread is already
in a waitpid(..., __WALL))

Note that the use of waitid was switched to waitpid, because waitid
doesn't support __WCLONE until kernel version 4.7.

Bug: none
Test: "debuggerd -b `pidof zygote64`" a few times (failed roughly 50%
      of the time previously)
Change-Id: Ia41a26a61f13c6f9aa85c4c2f88aef8d279d35ad
parent 85bcaf68
Loading
Loading
Loading
Loading
+5 −3
Original line number Original line Diff line number Diff line
@@ -197,7 +197,7 @@ static int debuggerd_dispatch_pseudothread(void* arg) {
  }
  }


  // Don't use fork(2) to avoid calling pthread_atfork handlers.
  // Don't use fork(2) to avoid calling pthread_atfork handlers.
  int forkpid = clone(nullptr, nullptr, SIGCHLD, nullptr);
  int forkpid = clone(nullptr, nullptr, 0, nullptr);
  if (forkpid == -1) {
  if (forkpid == -1) {
    __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to fork in debuggerd signal handler: %s",
    __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to fork in debuggerd signal handler: %s",
                      strerror(errno));
                      strerror(errno));
@@ -237,10 +237,12 @@ static int debuggerd_dispatch_pseudothread(void* arg) {
    close(pipefds[0]);
    close(pipefds[0]);


    // Don't leave a zombie child.
    // Don't leave a zombie child.
    siginfo_t child_siginfo;
    int status;
    if (TEMP_FAILURE_RETRY(waitid(P_PID, forkpid, &child_siginfo, WEXITED)) != 0) {
    if (TEMP_FAILURE_RETRY(waitpid(forkpid, &status, __WCLONE)) == -1 && errno != ECHILD) {
      __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s",
      __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s",
                        strerror(errno));
                        strerror(errno));
    } else if (WIFSTOPPED(status) || WIFSIGNALED(status)) {
      __libc_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper crashed or stopped");
      thread_info->crash_dump_started = false;
      thread_info->crash_dump_started = false;
    }
    }
  }
  }