2 * Copyright (C) 2007 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.internal.os;
19 import android.net.Credentials;
20 import android.net.LocalSocket;
21 import android.os.Process;
22 import android.os.SystemProperties;
23 import android.util.Log;
25 import dalvik.system.PathClassLoader;
26 import dalvik.system.Zygote;
28 import java.io.BufferedReader;
29 import java.io.DataOutputStream;
30 import java.io.FileDescriptor;
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.io.InputStreamReader;
34 import java.io.PrintStream;
35 import java.util.ArrayList;
38 * A connection that can make spawn requests.
40 class ZygoteConnection {
41 private static final String TAG = "Zygote";
43 /** a prototype instance for a future List.toArray() */
44 private static final int[][] intArray2d = new int[0][0];
47 * {@link android.net.LocalSocket#setSoTimeout} value for connections.
48 * Effectively, the amount of time a requestor has between the start of
49 * the request and the completed request. The select-loop mode Zygote
50 * doesn't have the logic to return to the select loop in the middle of
51 * a request, so we need to time out here to avoid being denial-of-serviced.
53 private static final int CONNECTION_TIMEOUT_MILLIS = 1000;
55 /** max number of arguments that a connection can specify */
56 private static final int MAX_ZYGOTE_ARGC=1024;
61 * mSocket is retained in the child process in "peer wait" mode, so
62 * that it closes when the child process terminates. In other cases,
63 * it is closed in the peer.
65 private final LocalSocket mSocket;
66 private final DataOutputStream mSocketOutStream;
67 private final BufferedReader mSocketReader;
68 private final Credentials peer;
71 * A long-lived reference to the original command socket used to launch
72 * this peer. If "peer wait" mode is specified, the process that requested
73 * the new VM instance intends to track the lifetime of the spawned instance
74 * via the command socket. In this case, the command socket is closed
75 * in the Zygote and placed here in the spawned instance so that it will
76 * not be collected and finalized. This field remains null at all times
77 * in the original Zygote process, and in all spawned processes where
78 * "peer-wait" mode was not requested.
80 private static LocalSocket sPeerWaitSocket = null;
83 * Constructs instance from connected socket.
85 * @param socket non-null; connected socket
88 ZygoteConnection(LocalSocket socket) throws IOException {
92 = new DataOutputStream(socket.getOutputStream());
94 mSocketReader = new BufferedReader(
95 new InputStreamReader(socket.getInputStream()), 256);
97 mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
100 peer = mSocket.getPeerCredentials();
101 } catch (IOException ex) {
102 Log.e(TAG, "Cannot read peer credentials", ex);
108 * Returns the file descriptor of the associated socket.
110 * @return null-ok; file descriptor
112 FileDescriptor getFileDesciptor() {
113 return mSocket.getFileDescriptor();
117 * Reads start commands from an open command socket.
118 * Start commands are presently a pair of newline-delimited lines
119 * indicating a) class to invoke main() on b) nice name to set argv[0] to.
120 * Continues to read commands and forkAndSpecialize children until
121 * the socket is closed. This method is used in ZYGOTE_FORK_MODE
123 * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main()
124 * method in child process
126 void run() throws ZygoteInit.MethodAndArgsCaller {
128 int loopCount = ZygoteInit.GC_LOOP_COUNT;
132 * Call gc() before we block in readArgumentList().
133 * It's work that has to be done anyway, and it's better
134 * to avoid making every child do it. It will also
135 * madvise() any free memory as a side-effect.
137 * Don't call it every time, because walking the entire
138 * heap is a lot of overhead to free a few hundred bytes.
140 if (loopCount <= 0) {
142 loopCount = ZygoteInit.GC_LOOP_COUNT;
154 * Reads one start command from the command socket. If successful,
155 * a child is forked and a {@link ZygoteInit.MethodAndArgsCaller}
156 * exception is thrown in that child while in the parent process,
157 * the method returns normally. On failure, the child is not
158 * spawned and messages are printed to the log and stderr. Returns
159 * a boolean status value indicating whether an end-of-file on the command
160 * socket has been encountered.
162 * @return false if command socket should continue to be read from, or
163 * true if an end-of-file has been encountered.
164 * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main()
165 * method in child process
167 boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
170 Arguments parsedArgs = null;
171 FileDescriptor[] descriptors;
174 args = readArgumentList();
175 descriptors = mSocket.getAncillaryFileDescriptors();
176 } catch (IOException ex) {
177 Log.w(TAG, "IOException on command socket " + ex.getMessage());
188 /** the stderr of the most recent request, if avail */
189 PrintStream newStderr = null;
191 if (descriptors != null && descriptors.length >= 3) {
192 newStderr = new PrintStream(
193 new FileOutputStream(descriptors[2]));
199 parsedArgs = new Arguments(args);
201 applyUidSecurityPolicy(parsedArgs, peer);
202 applyDebuggerSecurityPolicy(parsedArgs);
203 applyRlimitSecurityPolicy(parsedArgs, peer);
204 applyCapabilitiesSecurityPolicy(parsedArgs, peer);
206 int[][] rlimits = null;
208 if (parsedArgs.rlimits != null) {
209 rlimits = parsedArgs.rlimits.toArray(intArray2d);
212 pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
213 parsedArgs.gids, parsedArgs.debugFlags, rlimits);
214 } catch (IllegalArgumentException ex) {
215 logAndPrintError (newStderr, "Invalid zygote arguments", ex);
217 } catch (ZygoteSecurityException ex) {
218 logAndPrintError(newStderr,
219 "Zygote security policy prevents request: ", ex);
225 handleChildProc(parsedArgs, descriptors, newStderr);
226 // should never happen
228 } else { /* pid != 0 */
229 // in parent...pid of < 0 means failure
230 return handleParentProc(pid, descriptors, parsedArgs);
235 * Closes socket associated with this connection.
240 } catch (IOException ex) {
241 Log.e(TAG, "Exception while closing command "
242 + "socket in parent", ex);
247 * Handles argument parsing for args related to the zygote spawner.<p>
249 * Current recognized args:
251 * <li> --setuid=<i>uid of child process, defaults to 0</i>
252 * <li> --setgid=<i>gid of child process, defaults to 0</i>
253 * <li> --setgroups=<i>comma-separated list of supplimentary gid's</i>
254 * <li> --capabilities=<i>a pair of comma-separated integer strings
255 * indicating Linux capabilities(2) set for child. The first string
256 * represents the <code>permitted</code> set, and the second the
257 * <code>effective</code> set. Precede each with 0 or
258 * 0x for octal or hexidecimal value. If unspecified, both default to 0.
259 * This parameter is only applied if the uid of the new process will
261 * <li> --rlimit=r,c,m<i>tuple of values for setrlimit() call.
262 * <code>r</code> is the resource, <code>c</code> and <code>m</code>
263 * are the settings for current and max value.</i>
264 * <li> --peer-wait indicates that the command socket should
265 * be inherited by (and set to close-on-exec in) the spawned process
266 * and used to track the lifetime of that process. The spawning process
267 * then exits. Without this flag, it is retained by the spawning process
268 * (and closed in the child) in expectation of a new spawn request.
269 * <li> --classpath=<i>colon-separated classpath</i> indicates
270 * that the specified class (which must b first non-flag argument) should
271 * be loaded from jar files in the specified classpath. Incompatible with
273 * <li> --runtime-init indicates that the remaining arg list should
274 * be handed off to com.android.internal.os.RuntimeInit, rather than
276 * Android runtime startup (eg, Binder initialization) is also eschewed.
277 * <li> If <code>--runtime-init</code> is present:
278 * [--] <args for RuntimeInit >
279 * <li> If <code>--runtime-init</code> is absent:
280 * [--] <classname> [args...]
283 static class Arguments {
286 boolean uidSpecified;
290 boolean gidSpecified;
292 /** from --setgroups */
295 /** from --peer-wait */
299 * From --enable-debugger, --enable-checkjni, --enable-assert, and
304 /** from --classpath */
307 /** from --runtime-init */
310 /** from --capabilities */
311 boolean capabilitiesSpecified;
312 long permittedCapabilities;
313 long effectiveCapabilities;
315 /** from all --rlimit=r,c,m */
316 ArrayList<int[]> rlimits;
319 * Any args after and including the first non-option arg
322 String remainingArgs[];
325 * Constructs instance and parses args
326 * @param args zygote command-line args
327 * @throws IllegalArgumentException
329 Arguments(String args[]) throws IllegalArgumentException {
334 * Parses the commandline arguments intended for the Zygote spawner
335 * (such as "--setuid=" and "--setgid=") and creates an array
336 * containing the remaining args.
338 * Per security review bug #1112214, duplicate args are disallowed in
339 * critical cases to make injection harder.
341 private void parseArgs(String args[])
342 throws IllegalArgumentException {
345 for ( /* curArg */ ; curArg < args.length; curArg++) {
346 String arg = args[curArg];
348 if (arg.equals("--")) {
351 } else if (arg.startsWith("--setuid=")) {
353 throw new IllegalArgumentException(
354 "Duplicate arg specified");
357 uid = Integer.parseInt(
358 arg.substring(arg.indexOf('=') + 1));
359 } else if (arg.startsWith("--setgid=")) {
361 throw new IllegalArgumentException(
362 "Duplicate arg specified");
365 gid = Integer.parseInt(
366 arg.substring(arg.indexOf('=') + 1));
367 } else if (arg.equals("--enable-debugger")) {
368 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
369 } else if (arg.equals("--enable-safemode")) {
370 debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
371 } else if (arg.equals("--enable-checkjni")) {
372 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
373 } else if (arg.equals("--enable-assert")) {
374 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
375 } else if (arg.equals("--peer-wait")) {
377 } else if (arg.equals("--runtime-init")) {
379 } else if (arg.startsWith("--capabilities=")) {
380 if (capabilitiesSpecified) {
381 throw new IllegalArgumentException(
382 "Duplicate arg specified");
384 capabilitiesSpecified = true;
385 String capString = arg.substring(arg.indexOf('=')+1);
387 String[] capStrings = capString.split(",", 2);
389 if (capStrings.length == 1) {
390 effectiveCapabilities = Long.decode(capStrings[0]);
391 permittedCapabilities = effectiveCapabilities;
393 permittedCapabilities = Long.decode(capStrings[0]);
394 effectiveCapabilities = Long.decode(capStrings[1]);
396 } else if (arg.startsWith("--rlimit=")) {
397 // Duplicate --rlimit arguments are specifically allowed.
398 String[] limitStrings
399 = arg.substring(arg.indexOf('=')+1).split(",");
401 if (limitStrings.length != 3) {
402 throw new IllegalArgumentException(
403 "--rlimit= should have 3 comma-delimited ints");
405 int[] rlimitTuple = new int[limitStrings.length];
407 for(int i=0; i < limitStrings.length; i++) {
408 rlimitTuple[i] = Integer.parseInt(limitStrings[i]);
411 if (rlimits == null) {
412 rlimits = new ArrayList();
415 rlimits.add(rlimitTuple);
416 } else if (arg.equals("-classpath")) {
417 if (classpath != null) {
418 throw new IllegalArgumentException(
419 "Duplicate arg specified");
422 classpath = args[++curArg];
423 } catch (IndexOutOfBoundsException ex) {
424 throw new IllegalArgumentException(
425 "-classpath requires argument");
427 } else if (arg.startsWith("--setgroups=")) {
429 throw new IllegalArgumentException(
430 "Duplicate arg specified");
434 = arg.substring(arg.indexOf('=') + 1).split(",");
436 gids = new int[params.length];
438 for (int i = params.length - 1; i >= 0 ; i--) {
439 gids[i] = Integer.parseInt(params[i]);
446 if (runtimeInit && classpath != null) {
447 throw new IllegalArgumentException(
448 "--runtime-init and -classpath are incompatible");
451 remainingArgs = new String[args.length - curArg];
453 System.arraycopy(args, curArg, remainingArgs, 0,
454 remainingArgs.length);
459 * Reads an argument list from the command socket/
460 * @return Argument list or null if EOF is reached
461 * @throws IOException passed straight through
463 private String[] readArgumentList()
467 * See android.os.Process.zygoteSendArgsAndGetPid()
468 * Presently the wire format to the zygote process is:
469 * a) a count of arguments (argc, in essence)
470 * b) a number of newline-separated argument strings equal to count
472 * After the zygote process reads these it will write the pid of
473 * the child or -1 on failure.
479 String s = mSocketReader.readLine();
485 argc = Integer.parseInt(s);
486 } catch (NumberFormatException ex) {
487 Log.e(TAG, "invalid Zygote wire format: non-int at argc");
488 throw new IOException("invalid wire format");
491 // See bug 1092107: large argc can be used for a DOS attack
492 if (argc > MAX_ZYGOTE_ARGC) {
493 throw new IOException("max arg count exceeded");
496 String[] result = new String[argc];
497 for (int i = 0; i < argc; i++) {
498 result[i] = mSocketReader.readLine();
499 if (result[i] == null) {
500 // We got an unexpected EOF.
501 throw new IOException("truncated request");
509 * Applies zygote security policy per bugs #875058 and #1082165.
510 * Based on the credentials of the process issuing a zygote command:
512 * <li> uid 0 (root) may specify any uid, gid, and setgroups() list
513 * <li> uid 1000 (Process.SYSTEM_UID) may specify any uid > 1000 in normal
514 * operation. It may also specify any gid and setgroups() list it chooses.
515 * In factory test mode, it may specify any UID.
516 * <li> Any other uid may not specify any uid, gid, or setgroups list. The
517 * uid and gid will be inherited from the requesting process.
520 * @param args non-null; zygote spawner arguments
521 * @param peer non-null; peer credentials
522 * @throws ZygoteSecurityException
524 private static void applyUidSecurityPolicy(Arguments args, Credentials peer)
525 throws ZygoteSecurityException {
527 int peerUid = peer.getUid();
530 // Root can do what it wants
531 } else if (peerUid == Process.SYSTEM_UID ) {
532 // System UID is restricted, except in factory test mode
533 String factoryTest = SystemProperties.get("ro.factorytest");
534 boolean uidRestricted;
536 /* In normal operation, SYSTEM_UID can only specify a restricted
537 * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
540 = !(factoryTest.equals("1") || factoryTest.equals("2"));
543 && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) {
544 throw new ZygoteSecurityException(
545 "System UID may not launch process with UID < "
546 + Process.SYSTEM_UID);
550 if (args.uidSpecified || args.gidSpecified
551 || args.gids != null) {
552 throw new ZygoteSecurityException(
553 "App UIDs may not specify uid's or gid's");
557 // If not otherwise specified, uid and gid are inherited from peer
558 if (!args.uidSpecified) {
559 args.uid = peer.getUid();
560 args.uidSpecified = true;
562 if (!args.gidSpecified) {
563 args.gid = peer.getGid();
564 args.gidSpecified = true;
570 * Applies debugger security policy.
571 * If "ro.debuggable" is "1", all apps are debuggable. Otherwise,
572 * the debugger state is specified via the "--enable-debugger" flag
573 * in the spawn request.
575 * @param args non-null; zygote spawner args
577 private static void applyDebuggerSecurityPolicy(Arguments args) {
578 if ("1".equals(SystemProperties.get("ro.debuggable"))) {
579 args.debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
584 * Applies zygote security policy per bug #1042973. Based on the credentials
585 * of the process issuing a zygote command:
587 * <li> peers of uid 0 (root) and uid 1000 (Process.SYSTEM_UID)
588 * may specify any rlimits.
589 * <li> All other uids may not specify rlimits.
591 * @param args non-null; zygote spawner arguments
592 * @param peer non-null; peer credentials
593 * @throws ZygoteSecurityException
595 private static void applyRlimitSecurityPolicy(
596 Arguments args, Credentials peer)
597 throws ZygoteSecurityException {
599 int peerUid = peer.getUid();
601 if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) {
602 // All peers with UID other than root or SYSTEM_UID
603 if (args.rlimits != null) {
604 throw new ZygoteSecurityException(
605 "This UID may not specify rlimits.");
611 * Applies zygote security policy per bug #1042973. A root peer may
612 * spawn an instance with any capabilities. All other uids may spawn
613 * instances with any of the capabilities in the peer's permitted set
616 * @param args non-null; zygote spawner arguments
617 * @param peer non-null; peer credentials
618 * @throws ZygoteSecurityException
620 private static void applyCapabilitiesSecurityPolicy(
621 Arguments args, Credentials peer)
622 throws ZygoteSecurityException {
624 if (args.permittedCapabilities == 0
625 && args.effectiveCapabilities == 0) {
630 if (peer.getUid() == 0) {
631 // root may specify anything
638 permittedCaps = ZygoteInit.capgetPermitted(peer.getPid());
639 } catch (IOException ex) {
640 throw new ZygoteSecurityException(
641 "Error retrieving peer's capabilities.");
645 * Ensure that the client did not specify an effective set larger
646 * than the permitted set. The kernel will enforce this too, but we
647 * do it here to make the following check easier.
649 if (((~args.permittedCapabilities) & args.effectiveCapabilities) != 0) {
650 throw new ZygoteSecurityException(
651 "Effective capabilities cannot be superset of "
652 + " permitted capabilities" );
656 * Ensure that the new permitted (and thus the new effective) set is
657 * a subset of the peer process's permitted set
660 if (((~permittedCaps) & args.permittedCapabilities) != 0) {
661 throw new ZygoteSecurityException(
662 "Peer specified unpermitted capabilities" );
667 * Handles post-fork setup of child proc, closing sockets as appropriate,
668 * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
669 * if successful or returning if failed.
671 * @param parsedArgs non-null; zygote args
672 * @param descriptors null-ok; new file descriptors for stdio if available.
673 * @param newStderr null-ok; stream to use for stderr until stdio
676 * @throws ZygoteInit.MethodAndArgsCaller on success to
677 * trampoline to code that invokes static main.
679 private void handleChildProc(Arguments parsedArgs,
680 FileDescriptor[] descriptors, PrintStream newStderr)
681 throws ZygoteInit.MethodAndArgsCaller {
684 * Close the socket, unless we're in "peer wait" mode, in which
685 * case it's used to track the liveness of this process.
688 if (parsedArgs.peerWait) {
690 ZygoteInit.setCloseOnExec(mSocket.getFileDescriptor(), true);
691 sPeerWaitSocket = mSocket;
692 } catch (IOException ex) {
693 Log.e(TAG, "Zygote Child: error setting peer wait "
694 + "socket to be close-on-exec", ex);
698 ZygoteInit.closeServerSocket();
701 if (descriptors != null) {
703 ZygoteInit.reopenStdio(descriptors[0],
704 descriptors[1], descriptors[2]);
706 for (FileDescriptor fd: descriptors) {
707 ZygoteInit.closeDescriptor(fd);
709 newStderr = System.err;
710 } catch (IOException ex) {
711 Log.e(TAG, "Error reopening stdio", ex);
715 if (parsedArgs.runtimeInit) {
716 RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
720 if (parsedArgs.classpath != null) {
722 = new PathClassLoader(parsedArgs.classpath,
723 ClassLoader.getSystemClassLoader());
725 cloader = ClassLoader.getSystemClassLoader();
730 className = parsedArgs.remainingArgs[0];
731 } catch (ArrayIndexOutOfBoundsException ex) {
732 logAndPrintError (newStderr,
733 "Missing required class name argument", null);
737 = new String[parsedArgs.remainingArgs.length - 1];
739 System.arraycopy(parsedArgs.remainingArgs, 1,
740 mainArgs, 0, mainArgs.length);
743 ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
744 } catch (RuntimeException ex) {
745 logAndPrintError (newStderr, "Error starting. ", ex);
751 * Handles post-fork cleanup of parent proc
753 * @param pid != 0; pid of child if > 0 or indication of failed fork
755 * @param descriptors null-ok; file descriptors for child's new stdio if
757 * @param parsedArgs non-null; zygote args
758 * @return true for "exit command loop" and false for "continue command
761 private boolean handleParentProc(int pid,
762 FileDescriptor[] descriptors, Arguments parsedArgs) {
765 // Try to move the new child into the peer's process group.
767 ZygoteInit.setpgid(pid, ZygoteInit.getpgid(peer.getPid()));
768 } catch (IOException ex) {
769 // This exception is expected in the case where
770 // the peer is not in our session
771 // TODO get rid of this log message in the case where
772 // getsid(0) != getsid(peer.getPid())
773 Log.i(TAG, "Zygote: setpgid failed. This is "
774 + "normal if peer is not in our session");
779 if (descriptors != null) {
780 for (FileDescriptor fd: descriptors) {
781 ZygoteInit.closeDescriptor(fd);
784 } catch (IOException ex) {
785 Log.e(TAG, "Error closing passed descriptors in "
786 + "parent process", ex);
790 mSocketOutStream.writeInt(pid);
791 } catch (IOException ex) {
792 Log.e(TAG, "Error reading from command socket", ex);
797 * If the peer wants to use the socket to wait on the
798 * newly spawned process, then we're all done.
800 if (parsedArgs.peerWait) {
803 } catch (IOException ex) {
804 Log.e(TAG, "Zygote: error closing sockets", ex);
812 * Logs an error message and prints it to the specified stream, if
815 * @param newStderr null-ok; a standard error stream
816 * @param message non-null; error message
817 * @param ex null-ok an exception
819 private static void logAndPrintError (PrintStream newStderr,
820 String message, Throwable ex) {
821 Log.e(TAG, message, ex);
822 if (newStderr != null) {
823 newStderr.println(message + (ex == null ? "" : ex));