summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Platt <dplatt@google.com>2014-02-05 17:03:16 -0800
committerSteve Kondik <shade@chemlab.org>2014-02-19 23:17:11 -0800
commit24ea45165731eeda53217fce1de1c6b67ee0efb4 (patch)
treece4648509ca4e9823bc79f1721aaceacec9651d9
parentc44bb1e7e086884f30d41f64ee3b5cb4032253b5 (diff)
downloadandroid_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.cc56
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"),
};