From 7551899e52da74feabc308fd610ef3757695f885 Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Mon, 7 Nov 2016 16:22:48 +0000 Subject: Zygote : Block SIGCHLD during fork. Fix merge conflict into mnc-mr2-release 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 e9a525829a354c92983a35455ccab16d1b0d3892) Zygote: Unblock SIGCHLD in the parent after fork. Follow up to change e9a525829a354c92983a. Allows the zygote to receive SIGCHLD again and prevents the zygote from getting into a zombie state if it's killed. Contributed-By: rhed_jao Bug: 32693692 Test: manual (cherry picked from commit 1480dc3e97b661f5bfa3a5c2fbce72385b8d2be6) Change-Id: If89903a29c84dfc9b056f9e19618046874bba689 --- core/jni/com_android_internal_os_Zygote.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 4f90bd9..8686444 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -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, NULL) == -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, NULL) == -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); @@ -628,11 +647,11 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra } else if (pid > 0) { // the parent process -#ifdef ENABLE_SCHED_BOOST - // unset scheduler knob - SetForkLoad(false); -#endif - + // We blocked SIGCHLD prior to a fork, we unblock it here. + if (sigprocmask(SIG_UNBLOCK, &sigchld, NULL) == -1) { + ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)); + RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed."); + } } return pid; } -- cgit v1.1