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

Commit b6f37515 authored by Narayan Kamath's avatar Narayan Kamath Committed by Brian Carlstrom
Browse files

Zygote : Block SIGCHLD during fork.



We close the android logging related sockets prior as late as possible
before every fork to avoid having to whitelist them. If one of the
zygote's children dies after this point (but prior to the fork), we can
end up reopening the logging sockets from the SIGCHLD signal handler.

To prevent this from happening, block SIGCHLD during this critical
section.

Bug: 32693692
Test: Manual

(cherry picked from commit e9a52582)

Zygote: Unblock SIGCHLD in the parent after fork.

Follow up to change e9a52582. Allows the zygote to
receive SIGCHLD again and prevents the zygote from getting into a
zombie state if it's killed.

Contributed-By: default avatarrhed_jao <rhed_jao@htc.com>
Bug: 32693692
Test: manual

(cherry picked from commit c7161f756e86b98f2244a04d9207b47149965fd7)

Change-Id: If89903a29c84dfc9b056f9e19618046874bba689
(cherry picked from commit dfcc79ee)
parent 330d0ebf
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -465,6 +465,20 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
  SetForkLoad(true);
#endif

  sigset_t sigchld;
  sigemptyset(&sigchld);
  sigaddset(&sigchld, SIGCHLD);

  // Temporarily block SIGCHLD during forks. The SIGCHLD handler might
  // log, which would result in the logging FDs we close being reopened.
  // This would cause failures because the FDs are not whitelisted.
  //
  // Note that the zygote process is single threaded at this point.
  if (sigprocmask(SIG_BLOCK, &sigchld, nullptr) == -1) {
    ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
    RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_BLOCK, { SIGCHLD }) failed.");
  }

  // Close any logging related FDs before we start evaluating the list of
  // file descriptors.
  __android_log_close();
@@ -496,6 +510,11 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
      RuntimeAbort(env, __LINE__, "Unable to reopen whitelisted descriptors.");
    }

    if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
      ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
      RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed.");
    }

    // Keep capabilities across UID change, unless we're staying root.
    if (uid != 0) {
      EnableKeepCapabilities(env);
@@ -633,6 +652,11 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
    SetForkLoad(false);
#endif

    // We blocked SIGCHLD prior to a fork, we unblock it here.
    if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
      ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
      RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed.");
    }
  }
  return pid;
}