summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Platt <dplatt@google.com>2014-02-05 17:03:52 -0800
committerSteve Kondik <shade@chemlab.org>2014-02-19 23:17:46 -0800
commit0ba2fc83a4d25ee8781ca5030a365231cf46c5b9 (patch)
tree8d729ad3cfb29a6d6d30de6e91072c007444128a
parentbbe2d7a66c3678f5514c73c8e18ebffadf889431 (diff)
downloadandroid_dalvik-0ba2fc83a4d25ee8781ca5030a365231cf46c5b9.tar.gz
android_dalvik-0ba2fc83a4d25ee8781ca5030a365231cf46c5b9.tar.bz2
android_dalvik-0ba2fc83a4d25ee8781ca5030a365231cf46c5b9.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: 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",