aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Platt <dplatt@google.com>2014-02-05 17:03:52 -0800
committerLorDClockaN <davor@losinj.com>2014-02-21 18:24:46 +0100
commita7607232a38b7650d67be3556bddbf338771df8a (patch)
tree939475e4e6babb94dad528bb32b54a052af2b090
parentee44ed6acda1660143db76396fd6d4b9dd6d5d39 (diff)
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: whitespace Bug: 12114500 Change-Id: I989c83291d0c42d4cad63f24a3e98a93e231c9d3
-rw-r--r--vm/native/dalvik_system_Zygote.cpp79
1 files changed, 76 insertions, 3 deletions
diff --git a/vm/native/dalvik_system_Zygote.cpp b/vm/native/dalvik_system_Zygote.cpp
index 995268c3f..fa0cb51fa 100644
--- a/vm/native/dalvik_system_Zygote.cpp
+++ b/vm/native/dalvik_system_Zygote.cpp
@@ -34,6 +34,8 @@
#include <grp.h>
#include <errno.h>
#include <paths.h>
+#include <fcntl.h>
+#include <unistd.h>
#include <sys/personality.h>
#include <sys/stat.h>
#include <sys/mount.h>
@@ -504,6 +506,45 @@ static bool needsNoRandomizeWorkaround() {
#endif
}
+#ifdef HAVE_ANDROID_OS
+
+// 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(ArrayObject* fdsToClose) {
+ if (!fdsToClose) {
+ return;
+ }
+ size_t count = fdsToClose->length;
+ int *ar = (int *) (void *) fdsToClose->contents;
+ if (!ar) {
+ ALOG(LOG_ERROR, ZYGOTE_LOG_TAG, "Bad fd array");
+ dvmAbort();
+ }
+ size_t i;
+ int devnull;
+ for (i = 0; i < count; i++) {
+ if (ar[1] < 0) {
+ continue;
+ }
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull < 0) {
+ ALOG(LOG_ERROR, ZYGOTE_LOG_TAG, "Failed to open /dev/null");
+ dvmAbort();
+ }
+ ALOG(LOG_VERBOSE, ZYGOTE_LOG_TAG, "Switching descriptor %d to /dev/null", ar[i]);
+ if (dup2(devnull, ar[i]) < 0) {
+ ALOG(LOG_ERROR, ZYGOTE_LOG_TAG, "Failed dup2() on descriptor %d", ar[i]);
+ dvmAbort();
+ }
+ close(devnull);
+ }
+}
+
+#endif
+
/*
* Basic KSM Support
*/
@@ -565,7 +606,7 @@ static inline void pushAnonymousPagesToKSM(void)
/*
* Utility routine to fork zygote and specialize the child process.
*/
-static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
+static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer, bool legacyFork)
{
pid_t pid;
@@ -574,6 +615,7 @@ static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
ArrayObject* gids = (ArrayObject *)args[2];
u4 debugFlags = args[3];
ArrayObject *rlimits = (ArrayObject *)args[4];
+ ArrayObject *fdsToClose = NULL;
u4 mountMode = MOUNT_EXTERNAL_NONE;
int64_t permittedCapabilities, effectiveCapabilities;
char *seInfo = NULL;
@@ -608,6 +650,9 @@ static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
dvmAbort();
}
}
+ if (!legacyFork) {
+ fdsToClose = (ArrayObject *)args[8];
+ }
}
if (!gDvm.zygote) {
@@ -635,6 +680,10 @@ static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
extern int gMallocLeakZygoteChild;
gMallocLeakZygoteChild = 1;
+ // Unhook from the Zygote sockets immediately
+
+ detachDescriptors(fdsToClose);
+
/* keep caps across UID change, unless we're staying root */
if (uid != 0) {
err = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
@@ -768,6 +817,28 @@ static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
}
/*
+ * We must expose both flavors of the native forking code for a while,
+ * as this Dalvik change must be reviewed and checked in before the
+ * libcore and frameworks changes. The legacy fork API function and
+ * registration can be removed later.
+ */
+
+/*
+ * native public static int nativeForkAndSpecialize(int uid, int gid,
+ * int[] gids, int debugFlags, int[][] rlimits, int mountExternal,
+ * String seInfo, String niceName, int[] fdsToClose);
+ */
+static void Dalvik_dalvik_system_Zygote_forkAndSpecialize_new(const u4* args,
+ JValue* pResult)
+{
+ pid_t pid;
+
+ pid = forkAndSpecializeCommon(args, false, false);
+
+ RETURN_INT(pid);
+}
+
+/*
* native public static int nativeForkAndSpecialize(int uid, int gid,
* int[] gids, int debugFlags, int[][] rlimits, int mountExternal,
* String seInfo, String niceName);
@@ -777,7 +848,7 @@ static void Dalvik_dalvik_system_Zygote_forkAndSpecialize(const u4* args,
{
pid_t pid;
- pid = forkAndSpecializeCommon(args, false);
+ pid = forkAndSpecializeCommon(args, false, true);
RETURN_INT(pid);
}
@@ -791,7 +862,7 @@ static void Dalvik_dalvik_system_Zygote_forkSystemServer(
const u4* args, JValue* pResult)
{
pid_t pid;
- pid = forkAndSpecializeCommon(args, true);
+ pid = forkAndSpecializeCommon(args, true, true);
/* The zygote process checks whether the child process has died or not. */
if (pid > 0) {
@@ -814,6 +885,8 @@ static void Dalvik_dalvik_system_Zygote_forkSystemServer(
const DalvikNativeMethod dvm_dalvik_system_Zygote[] = {
{ "nativeFork", "()I",
Dalvik_dalvik_system_Zygote_fork },
+ { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I)I",
+ Dalvik_dalvik_system_Zygote_forkAndSpecialize_new },
{ "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;)I",
Dalvik_dalvik_system_Zygote_forkAndSpecialize },
{ "nativeForkSystemServer", "(II[II[[IJJ)I",