diff options
author | Dave Platt <dplatt@google.com> | 2014-02-05 17:03:16 -0800 |
---|---|---|
committer | Steve Kondik <shade@chemlab.org> | 2014-02-19 23:17:11 -0800 |
commit | 24ea45165731eeda53217fce1de1c6b67ee0efb4 (patch) | |
tree | ce4648509ca4e9823bc79f1721aaceacec9651d9 | |
parent | c44bb1e7e086884f30d41f64ee3b5cb4032253b5 (diff) | |
download | android_art-24ea45165731eeda53217fce1de1c6b67ee0efb4.tar.gz android_art-24ea45165731eeda53217fce1de1c6b67ee0efb4.tar.bz2 android_art-24ea45165731eeda53217fce1de1c6b67ee0efb4.zip |
Finish fixing Zygote descriptor leakage problem
In order to prevent Zygote descriptors from leaking into the child
environment, they should be closed by the forked-off child process
before the child switches to the application UID. These changes close
the descriptors via dup2(), substituting a descriptor open to
/dev/null in their place; this allows the Zygote Java code to close
the FileDescriptor objects cleanly.
This is a multi-project change: dalvik, art, libcore, frameworks/base,
and external/sepolicy are affected. The CLs need to be approved
together, lest the build break or the software fail to boot.
Round 2: use proper type (jsize) for iteration variable; whitespace.
Round 3: indentation.
Bug: 12114500
Change-Id: I31d25831b477b076d980c531d57773f9c8c83261
-rw-r--r-- | runtime/native/dalvik_system_Zygote.cc | 56 |
1 files changed, 51 insertions, 5 deletions
diff --git a/runtime/native/dalvik_system_Zygote.cc b/runtime/native/dalvik_system_Zygote.cc index 2acacc9959..d6cc24979e 100644 --- a/runtime/native/dalvik_system_Zygote.cc +++ b/runtime/native/dalvik_system_Zygote.cc @@ -23,8 +23,10 @@ #include <signal.h> #include <stdlib.h> #include <sys/types.h> +#include <sys/stat.h> #include <sys/wait.h> #include <unistd.h> +#include <fcntl.h> #include "cutils/fs.h" #include "cutils/multiuser.h" @@ -401,12 +403,43 @@ static bool NeedsNoRandomizeWorkaround() { } #endif +// Utility to close down the Zygote socket file descriptors while +// the child is still running as root with Zygote's privileges. Each +// descriptor (if any) is closed via dup2(), replacing it with a valid +// (open) descriptor to /dev/null. + +static void DetachDescriptors(JNIEnv* env, jintArray fdsToClose) { + if (!fdsToClose) { + return; + } + jsize count = env->GetArrayLength(fdsToClose); + jint *ar = env->GetIntArrayElements(fdsToClose, 0); + if (!ar) { + PLOG(FATAL) << "Bad fd array"; + } + jsize i; + int devnull; + for (i = 0; i < count; i++) { + devnull = open("/dev/null", O_RDWR); + if (devnull < 0) { + PLOG(FATAL) << "Failed to open /dev/null"; + continue; + } + PLOG(VERBOSE) << "Switching descriptor " << ar[i] << " to /dev/null"; + if (dup2(devnull, ar[i]) < 0) { + PLOG(FATAL) << "Failed dup2() on descriptor " << ar[i]; + } + close(devnull); + } +} + // Utility routine to fork zygote and specialize the child process. static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids, jint debug_flags, jobjectArray javaRlimits, jlong permittedCapabilities, jlong effectiveCapabilities, jint mount_external, - jstring java_se_info, jstring java_se_name, bool is_system_server) { + jstring java_se_info, jstring java_se_name, + bool is_system_server, jintArray fdsToClose) { Runtime* runtime = Runtime::Current(); CHECK(runtime->IsZygote()) << "runtime instance not started with -Xzygote"; if (!runtime->PreZygoteFork()) { @@ -425,6 +458,9 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra // The child process. gMallocLeakZygoteChild = 1; + // Clean up any descriptors which must be closed immediately + DetachDescriptors(env, fdsToClose); + // Keep capabilities across UID change, unless we're staying root. if (uid != 0) { EnableKeepCapabilities(); @@ -516,10 +552,19 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra return pid; } +static jint Zygote_nativeForkAndSpecialize_new(JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, + jint debug_flags, jobjectArray rlimits, + jint mount_external, jstring se_info, jstring se_name, + jintArray fdsToClose) { + return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags, rlimits, 0, 0, mount_external, + se_info, se_name, false, fdsToClose); +} + static jint Zygote_nativeForkAndSpecialize(JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, - jint debug_flags, jobjectArray rlimits, jint mount_external, - jstring se_info, jstring se_name) { - return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags, rlimits, 0, 0, mount_external, se_info, se_name, false); + jint debug_flags, jobjectArray rlimits, + jint mount_external, jstring se_info, jstring se_name) { + return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags, rlimits, 0, 0, mount_external, + se_info, se_name, false, NULL); } static jint Zygote_nativeForkSystemServer(JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids, @@ -528,7 +573,7 @@ static jint Zygote_nativeForkSystemServer(JNIEnv* env, jclass, uid_t uid, gid_t pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags, rlimits, permittedCapabilities, effectiveCapabilities, - MOUNT_EXTERNAL_NONE, NULL, NULL, true); + MOUNT_EXTERNAL_NONE, NULL, NULL, true, NULL); if (pid > 0) { // The zygote process checks whether the child process has died or not. LOG(INFO) << "System server process " << pid << " has been created"; @@ -545,6 +590,7 @@ static jint Zygote_nativeForkSystemServer(JNIEnv* env, jclass, uid_t uid, gid_t } static JNINativeMethod gMethods[] = { + NATIVE_METHOD(Zygote, nativeForkAndSpecialize_new, "(II[II[[IILjava/lang/String;Ljava/lang/String;[I)I"), NATIVE_METHOD(Zygote, nativeForkAndSpecialize, "(II[II[[IILjava/lang/String;Ljava/lang/String;)I"), NATIVE_METHOD(Zygote, nativeForkSystemServer, "(II[II[[IJJ)I"), }; |