Home | History | Annotate | Download | only in os
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      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
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     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.
     15  */
     16 
     17 package com.android.internal.os;
     18 
     19 import android.net.Credentials;
     20 import android.net.LocalSocket;
     21 import android.os.Build;
     22 import android.os.Process;
     23 import android.os.SystemProperties;
     24 import android.util.Log;
     25 
     26 import dalvik.system.PathClassLoader;
     27 import dalvik.system.Zygote;
     28 
     29 import java.io.BufferedReader;
     30 import java.io.DataInputStream;
     31 import java.io.DataOutputStream;
     32 import java.io.FileDescriptor;
     33 import java.io.FileInputStream;
     34 import java.io.FileOutputStream;
     35 import java.io.IOException;
     36 import java.io.InputStreamReader;
     37 import java.io.PrintStream;
     38 import java.util.ArrayList;
     39 
     40 import libcore.io.ErrnoException;
     41 import libcore.io.IoUtils;
     42 import libcore.io.Libcore;
     43 
     44 /**
     45  * A connection that can make spawn requests.
     46  */
     47 class ZygoteConnection {
     48     private static final String TAG = "Zygote";
     49 
     50     /** a prototype instance for a future List.toArray() */
     51     private static final int[][] intArray2d = new int[0][0];
     52 
     53     /**
     54      * {@link android.net.LocalSocket#setSoTimeout} value for connections.
     55      * Effectively, the amount of time a requestor has between the start of
     56      * the request and the completed request. The select-loop mode Zygote
     57      * doesn't have the logic to return to the select loop in the middle of
     58      * a request, so we need to time out here to avoid being denial-of-serviced.
     59      */
     60     private static final int CONNECTION_TIMEOUT_MILLIS = 1000;
     61 
     62     /** max number of arguments that a connection can specify */
     63     private static final int MAX_ZYGOTE_ARGC=1024;
     64 
     65     /**
     66      * The command socket.
     67      *
     68      * mSocket is retained in the child process in "peer wait" mode, so
     69      * that it closes when the child process terminates. In other cases,
     70      * it is closed in the peer.
     71      */
     72     private final LocalSocket mSocket;
     73     private final DataOutputStream mSocketOutStream;
     74     private final BufferedReader mSocketReader;
     75     private final Credentials peer;
     76 
     77     /**
     78      * A long-lived reference to the original command socket used to launch
     79      * this peer. If "peer wait" mode is specified, the process that requested
     80      * the new VM instance intends to track the lifetime of the spawned instance
     81      * via the command socket. In this case, the command socket is closed
     82      * in the Zygote and placed here in the spawned instance so that it will
     83      * not be collected and finalized. This field remains null at all times
     84      * in the original Zygote process, and in all spawned processes where
     85      * "peer-wait" mode was not requested.
     86      */
     87     private static LocalSocket sPeerWaitSocket = null;
     88 
     89     /**
     90      * Constructs instance from connected socket.
     91      *
     92      * @param socket non-null; connected socket
     93      * @throws IOException
     94      */
     95     ZygoteConnection(LocalSocket socket) throws IOException {
     96         mSocket = socket;
     97 
     98         mSocketOutStream
     99                 = new DataOutputStream(socket.getOutputStream());
    100 
    101         mSocketReader = new BufferedReader(
    102                 new InputStreamReader(socket.getInputStream()), 256);
    103 
    104         mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
    105 
    106         try {
    107             peer = mSocket.getPeerCredentials();
    108         } catch (IOException ex) {
    109             Log.e(TAG, "Cannot read peer credentials", ex);
    110             throw ex;
    111         }
    112     }
    113 
    114     /**
    115      * Returns the file descriptor of the associated socket.
    116      *
    117      * @return null-ok; file descriptor
    118      */
    119     FileDescriptor getFileDesciptor() {
    120         return mSocket.getFileDescriptor();
    121     }
    122 
    123     /**
    124      * Reads start commands from an open command socket.
    125      * Start commands are presently a pair of newline-delimited lines
    126      * indicating a) class to invoke main() on b) nice name to set argv[0] to.
    127      * Continues to read commands and forkAndSpecialize children until
    128      * the socket is closed. This method is used in ZYGOTE_FORK_MODE
    129      *
    130      * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main()
    131      * method in child process
    132      */
    133     void run() throws ZygoteInit.MethodAndArgsCaller {
    134 
    135         int loopCount = ZygoteInit.GC_LOOP_COUNT;
    136 
    137         while (true) {
    138             /*
    139              * Call gc() before we block in readArgumentList().
    140              * It's work that has to be done anyway, and it's better
    141              * to avoid making every child do it.  It will also
    142              * madvise() any free memory as a side-effect.
    143              *
    144              * Don't call it every time, because walking the entire
    145              * heap is a lot of overhead to free a few hundred bytes.
    146              */
    147             if (loopCount <= 0) {
    148                 ZygoteInit.gc();
    149                 loopCount = ZygoteInit.GC_LOOP_COUNT;
    150             } else {
    151                 loopCount--;
    152             }
    153 
    154             if (runOnce()) {
    155                 break;
    156             }
    157         }
    158     }
    159 
    160     /**
    161      * Reads one start command from the command socket. If successful,
    162      * a child is forked and a {@link ZygoteInit.MethodAndArgsCaller}
    163      * exception is thrown in that child while in the parent process,
    164      * the method returns normally. On failure, the child is not
    165      * spawned and messages are printed to the log and stderr. Returns
    166      * a boolean status value indicating whether an end-of-file on the command
    167      * socket has been encountered.
    168      *
    169      * @return false if command socket should continue to be read from, or
    170      * true if an end-of-file has been encountered.
    171      * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main()
    172      * method in child process
    173      */
    174     boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
    175 
    176         String args[];
    177         Arguments parsedArgs = null;
    178         FileDescriptor[] descriptors;
    179 
    180         try {
    181             args = readArgumentList();
    182             descriptors = mSocket.getAncillaryFileDescriptors();
    183         } catch (IOException ex) {
    184             Log.w(TAG, "IOException on command socket " + ex.getMessage());
    185             closeSocket();
    186             return true;
    187         }
    188 
    189         if (args == null) {
    190             // EOF reached.
    191             closeSocket();
    192             return true;
    193         }
    194 
    195         /** the stderr of the most recent request, if avail */
    196         PrintStream newStderr = null;
    197 
    198         if (descriptors != null && descriptors.length >= 3) {
    199             newStderr = new PrintStream(
    200                     new FileOutputStream(descriptors[2]));
    201         }
    202 
    203         int pid = -1;
    204         FileDescriptor childPipeFd = null;
    205         FileDescriptor serverPipeFd = null;
    206 
    207         try {
    208             parsedArgs = new Arguments(args);
    209 
    210             applyUidSecurityPolicy(parsedArgs, peer);
    211             applyRlimitSecurityPolicy(parsedArgs, peer);
    212             applyCapabilitiesSecurityPolicy(parsedArgs, peer);
    213             applyInvokeWithSecurityPolicy(parsedArgs, peer);
    214 
    215             applyDebuggerSystemProperty(parsedArgs);
    216             applyInvokeWithSystemProperty(parsedArgs);
    217 
    218             int[][] rlimits = null;
    219 
    220             if (parsedArgs.rlimits != null) {
    221                 rlimits = parsedArgs.rlimits.toArray(intArray2d);
    222             }
    223 
    224             if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) {
    225                 FileDescriptor[] pipeFds = Libcore.os.pipe();
    226                 childPipeFd = pipeFds[1];
    227                 serverPipeFd = pipeFds[0];
    228                 ZygoteInit.setCloseOnExec(serverPipeFd, true);
    229             }
    230 
    231             pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
    232                     parsedArgs.gids, parsedArgs.debugFlags, rlimits);
    233         } catch (IOException ex) {
    234             logAndPrintError(newStderr, "Exception creating pipe", ex);
    235         } catch (ErrnoException ex) {
    236             logAndPrintError(newStderr, "Exception creating pipe", ex);
    237         } catch (IllegalArgumentException ex) {
    238             logAndPrintError(newStderr, "Invalid zygote arguments", ex);
    239         } catch (ZygoteSecurityException ex) {
    240             logAndPrintError(newStderr,
    241                     "Zygote security policy prevents request: ", ex);
    242         }
    243 
    244         try {
    245             if (pid == 0) {
    246                 // in child
    247                 IoUtils.closeQuietly(serverPipeFd);
    248                 serverPipeFd = null;
    249                 handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
    250 
    251                 // should never get here, the child is expected to either
    252                 // throw ZygoteInit.MethodAndArgsCaller or exec().
    253                 return true;
    254             } else {
    255                 // in parent...pid of < 0 means failure
    256                 IoUtils.closeQuietly(childPipeFd);
    257                 childPipeFd = null;
    258                 return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
    259             }
    260         } finally {
    261             IoUtils.closeQuietly(childPipeFd);
    262             IoUtils.closeQuietly(serverPipeFd);
    263         }
    264     }
    265 
    266     /**
    267      * Closes socket associated with this connection.
    268      */
    269     void closeSocket() {
    270         try {
    271             mSocket.close();
    272         } catch (IOException ex) {
    273             Log.e(TAG, "Exception while closing command "
    274                     + "socket in parent", ex);
    275         }
    276     }
    277 
    278     /**
    279      * Handles argument parsing for args related to the zygote spawner.
    280      *
    281      * Current recognized args:
    282      * <ul>
    283      *   <li> --setuid=<i>uid of child process, defaults to 0</i>
    284      *   <li> --setgid=<i>gid of child process, defaults to 0</i>
    285      *   <li> --setgroups=<i>comma-separated list of supplimentary gid's</i>
    286      *   <li> --capabilities=<i>a pair of comma-separated integer strings
    287      * indicating Linux capabilities(2) set for child. The first string
    288      * represents the <code>permitted</code> set, and the second the
    289      * <code>effective</code> set. Precede each with 0 or
    290      * 0x for octal or hexidecimal value. If unspecified, both default to 0.
    291      * This parameter is only applied if the uid of the new process will
    292      * be non-0. </i>
    293      *   <li> --rlimit=r,c,m<i>tuple of values for setrlimit() call.
    294      *    <code>r</code> is the resource, <code>c</code> and <code>m</code>
    295      *    are the settings for current and max value.</i>
    296      *   <li> --peer-wait indicates that the command socket should
    297      * be inherited by (and set to close-on-exec in) the spawned process
    298      * and used to track the lifetime of that process. The spawning process
    299      * then exits. Without this flag, it is retained by the spawning process
    300      * (and closed in the child) in expectation of a new spawn request.
    301      *   <li> --classpath=<i>colon-separated classpath</i> indicates
    302      * that the specified class (which must b first non-flag argument) should
    303      * be loaded from jar files in the specified classpath. Incompatible with
    304      * --runtime-init
    305      *   <li> --runtime-init indicates that the remaining arg list should
    306      * be handed off to com.android.internal.os.RuntimeInit, rather than
    307      * processed directly
    308      * Android runtime startup (eg, Binder initialization) is also eschewed.
    309      *   <li> --nice-name=<i>nice name to appear in ps</i>
    310      *   <li> If <code>--runtime-init</code> is present:
    311      *      [--] &lt;args for RuntimeInit &gt;
    312      *   <li> If <code>--runtime-init</code> is absent:
    313      *      [--] &lt;classname&gt; [args...]
    314      * </ul>
    315      */
    316     static class Arguments {
    317         /** from --setuid */
    318         int uid = 0;
    319         boolean uidSpecified;
    320 
    321         /** from --setgid */
    322         int gid = 0;
    323         boolean gidSpecified;
    324 
    325         /** from --setgroups */
    326         int[] gids;
    327 
    328         /** from --peer-wait */
    329         boolean peerWait;
    330 
    331         /**
    332          * From --enable-debugger, --enable-checkjni, --enable-assert,
    333          * --enable-safemode, and --enable-jni-logging.
    334          */
    335         int debugFlags;
    336 
    337         /** from --target-sdk-version. */
    338         int targetSdkVersion;
    339         boolean targetSdkVersionSpecified;
    340 
    341         /** from --classpath */
    342         String classpath;
    343 
    344         /** from --runtime-init */
    345         boolean runtimeInit;
    346 
    347         /** from --nice-name */
    348         String niceName;
    349 
    350         /** from --capabilities */
    351         boolean capabilitiesSpecified;
    352         long permittedCapabilities;
    353         long effectiveCapabilities;
    354 
    355         /** from all --rlimit=r,c,m */
    356         ArrayList<int[]> rlimits;
    357 
    358         /** from --invoke-with */
    359         String invokeWith;
    360 
    361         /**
    362          * Any args after and including the first non-option arg
    363          * (or after a '--')
    364          */
    365         String remainingArgs[];
    366 
    367         /**
    368          * Constructs instance and parses args
    369          * @param args zygote command-line args
    370          * @throws IllegalArgumentException
    371          */
    372         Arguments(String args[]) throws IllegalArgumentException {
    373             parseArgs(args);
    374         }
    375 
    376         /**
    377          * Parses the commandline arguments intended for the Zygote spawner
    378          * (such as "--setuid=" and "--setgid=") and creates an array
    379          * containing the remaining args.
    380          *
    381          * Per security review bug #1112214, duplicate args are disallowed in
    382          * critical cases to make injection harder.
    383          */
    384         private void parseArgs(String args[])
    385                 throws IllegalArgumentException {
    386             int curArg = 0;
    387 
    388             for ( /* curArg */ ; curArg < args.length; curArg++) {
    389                 String arg = args[curArg];
    390 
    391                 if (arg.equals("--")) {
    392                     curArg++;
    393                     break;
    394                 } else if (arg.startsWith("--setuid=")) {
    395                     if (uidSpecified) {
    396                         throw new IllegalArgumentException(
    397                                 "Duplicate arg specified");
    398                     }
    399                     uidSpecified = true;
    400                     uid = Integer.parseInt(
    401                             arg.substring(arg.indexOf('=') + 1));
    402                 } else if (arg.startsWith("--setgid=")) {
    403                     if (gidSpecified) {
    404                         throw new IllegalArgumentException(
    405                                 "Duplicate arg specified");
    406                     }
    407                     gidSpecified = true;
    408                     gid = Integer.parseInt(
    409                             arg.substring(arg.indexOf('=') + 1));
    410                 } else if (arg.startsWith("--target-sdk-version=")) {
    411                     if (targetSdkVersionSpecified) {
    412                         throw new IllegalArgumentException(
    413                                 "Duplicate target-sdk-version specified");
    414                     }
    415                     targetSdkVersionSpecified = true;
    416                     targetSdkVersion = Integer.parseInt(
    417                             arg.substring(arg.indexOf('=') + 1));
    418                 } else if (arg.equals("--enable-debugger")) {
    419                     debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
    420                 } else if (arg.equals("--enable-safemode")) {
    421                     debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
    422                 } else if (arg.equals("--enable-checkjni")) {
    423                     debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
    424                 } else if (arg.equals("--enable-jni-logging")) {
    425                     debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
    426                 } else if (arg.equals("--enable-assert")) {
    427                     debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
    428                 } else if (arg.equals("--peer-wait")) {
    429                     peerWait = true;
    430                 } else if (arg.equals("--runtime-init")) {
    431                     runtimeInit = true;
    432                 } else if (arg.startsWith("--capabilities=")) {
    433                     if (capabilitiesSpecified) {
    434                         throw new IllegalArgumentException(
    435                                 "Duplicate arg specified");
    436                     }
    437                     capabilitiesSpecified = true;
    438                     String capString = arg.substring(arg.indexOf('=')+1);
    439 
    440                     String[] capStrings = capString.split(",", 2);
    441 
    442                     if (capStrings.length == 1) {
    443                         effectiveCapabilities = Long.decode(capStrings[0]);
    444                         permittedCapabilities = effectiveCapabilities;
    445                     } else {
    446                         permittedCapabilities = Long.decode(capStrings[0]);
    447                         effectiveCapabilities = Long.decode(capStrings[1]);
    448                     }
    449                 } else if (arg.startsWith("--rlimit=")) {
    450                     // Duplicate --rlimit arguments are specifically allowed.
    451                     String[] limitStrings
    452                             = arg.substring(arg.indexOf('=')+1).split(",");
    453 
    454                     if (limitStrings.length != 3) {
    455                         throw new IllegalArgumentException(
    456                                 "--rlimit= should have 3 comma-delimited ints");
    457                     }
    458                     int[] rlimitTuple = new int[limitStrings.length];
    459 
    460                     for(int i=0; i < limitStrings.length; i++) {
    461                         rlimitTuple[i] = Integer.parseInt(limitStrings[i]);
    462                     }
    463 
    464                     if (rlimits == null) {
    465                         rlimits = new ArrayList();
    466                     }
    467 
    468                     rlimits.add(rlimitTuple);
    469                 } else if (arg.equals("-classpath")) {
    470                     if (classpath != null) {
    471                         throw new IllegalArgumentException(
    472                                 "Duplicate arg specified");
    473                     }
    474                     try {
    475                         classpath = args[++curArg];
    476                     } catch (IndexOutOfBoundsException ex) {
    477                         throw new IllegalArgumentException(
    478                                 "-classpath requires argument");
    479                     }
    480                 } else if (arg.startsWith("--setgroups=")) {
    481                     if (gids != null) {
    482                         throw new IllegalArgumentException(
    483                                 "Duplicate arg specified");
    484                     }
    485 
    486                     String[] params
    487                             = arg.substring(arg.indexOf('=') + 1).split(",");
    488 
    489                     gids = new int[params.length];
    490 
    491                     for (int i = params.length - 1; i >= 0 ; i--) {
    492                         gids[i] = Integer.parseInt(params[i]);
    493                     }
    494                 } else if (arg.equals("--invoke-with")) {
    495                     if (invokeWith != null) {
    496                         throw new IllegalArgumentException(
    497                                 "Duplicate arg specified");
    498                     }
    499                     try {
    500                         invokeWith = args[++curArg];
    501                     } catch (IndexOutOfBoundsException ex) {
    502                         throw new IllegalArgumentException(
    503                                 "--invoke-with requires argument");
    504                     }
    505                 } else if (arg.startsWith("--nice-name=")) {
    506                     if (niceName != null) {
    507                         throw new IllegalArgumentException(
    508                                 "Duplicate arg specified");
    509                     }
    510                     niceName = arg.substring(arg.indexOf('=') + 1);
    511                 } else {
    512                     break;
    513                 }
    514             }
    515 
    516             if (runtimeInit && classpath != null) {
    517                 throw new IllegalArgumentException(
    518                         "--runtime-init and -classpath are incompatible");
    519             }
    520 
    521             remainingArgs = new String[args.length - curArg];
    522 
    523             System.arraycopy(args, curArg, remainingArgs, 0,
    524                     remainingArgs.length);
    525         }
    526     }
    527 
    528     /**
    529      * Reads an argument list from the command socket/
    530      * @return Argument list or null if EOF is reached
    531      * @throws IOException passed straight through
    532      */
    533     private String[] readArgumentList()
    534             throws IOException {
    535 
    536         /**
    537          * See android.os.Process.zygoteSendArgsAndGetPid()
    538          * Presently the wire format to the zygote process is:
    539          * a) a count of arguments (argc, in essence)
    540          * b) a number of newline-separated argument strings equal to count
    541          *
    542          * After the zygote process reads these it will write the pid of
    543          * the child or -1 on failure.
    544          */
    545 
    546         int argc;
    547 
    548         try {
    549             String s = mSocketReader.readLine();
    550 
    551             if (s == null) {
    552                 // EOF reached.
    553                 return null;
    554             }
    555             argc = Integer.parseInt(s);
    556         } catch (NumberFormatException ex) {
    557             Log.e(TAG, "invalid Zygote wire format: non-int at argc");
    558             throw new IOException("invalid wire format");
    559         }
    560 
    561         // See bug 1092107: large argc can be used for a DOS attack
    562         if (argc > MAX_ZYGOTE_ARGC) {
    563             throw new IOException("max arg count exceeded");
    564         }
    565 
    566         String[] result = new String[argc];
    567         for (int i = 0; i < argc; i++) {
    568             result[i] = mSocketReader.readLine();
    569             if (result[i] == null) {
    570                 // We got an unexpected EOF.
    571                 throw new IOException("truncated request");
    572             }
    573         }
    574 
    575         return result;
    576     }
    577 
    578     /**
    579      * Applies zygote security policy per bugs #875058 and #1082165.
    580      * Based on the credentials of the process issuing a zygote command:
    581      * <ol>
    582      * <li> uid 0 (root) may specify any uid, gid, and setgroups() list
    583      * <li> uid 1000 (Process.SYSTEM_UID) may specify any uid &gt; 1000 in normal
    584      * operation. It may also specify any gid and setgroups() list it chooses.
    585      * In factory test mode, it may specify any UID.
    586      * <li> Any other uid may not specify any uid, gid, or setgroups list. The
    587      * uid and gid will be inherited from the requesting process.
    588      * </ul>
    589      *
    590      * @param args non-null; zygote spawner arguments
    591      * @param peer non-null; peer credentials
    592      * @throws ZygoteSecurityException
    593      */
    594     private static void applyUidSecurityPolicy(Arguments args, Credentials peer)
    595             throws ZygoteSecurityException {
    596 
    597         int peerUid = peer.getUid();
    598 
    599         if (peerUid == 0) {
    600             // Root can do what it wants
    601         } else if (peerUid == Process.SYSTEM_UID ) {
    602             // System UID is restricted, except in factory test mode
    603             String factoryTest = SystemProperties.get("ro.factorytest");
    604             boolean uidRestricted;
    605 
    606             /* In normal operation, SYSTEM_UID can only specify a restricted
    607              * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
    608              */
    609             uidRestricted
    610                  = !(factoryTest.equals("1") || factoryTest.equals("2"));
    611 
    612             if (uidRestricted
    613                     && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) {
    614                 throw new ZygoteSecurityException(
    615                         "System UID may not launch process with UID < "
    616                                 + Process.SYSTEM_UID);
    617             }
    618         } else {
    619             // Everything else
    620             if (args.uidSpecified || args.gidSpecified
    621                 || args.gids != null) {
    622                 throw new ZygoteSecurityException(
    623                         "App UIDs may not specify uid's or gid's");
    624             }
    625         }
    626 
    627         // If not otherwise specified, uid and gid are inherited from peer
    628         if (!args.uidSpecified) {
    629             args.uid = peer.getUid();
    630             args.uidSpecified = true;
    631         }
    632         if (!args.gidSpecified) {
    633             args.gid = peer.getGid();
    634             args.gidSpecified = true;
    635         }
    636     }
    637 
    638 
    639     /**
    640      * Applies debugger system properties to the zygote arguments.
    641      *
    642      * If "ro.debuggable" is "1", all apps are debuggable. Otherwise,
    643      * the debugger state is specified via the "--enable-debugger" flag
    644      * in the spawn request.
    645      *
    646      * @param args non-null; zygote spawner args
    647      */
    648     public static void applyDebuggerSystemProperty(Arguments args) {
    649         if ("1".equals(SystemProperties.get("ro.debuggable"))) {
    650             args.debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
    651         }
    652     }
    653 
    654     /**
    655      * Applies zygote security policy per bug #1042973. Based on the credentials
    656      * of the process issuing a zygote command:
    657      * <ol>
    658      * <li> peers of  uid 0 (root) and uid 1000 (Process.SYSTEM_UID)
    659      * may specify any rlimits.
    660      * <li> All other uids may not specify rlimits.
    661      * </ul>
    662      * @param args non-null; zygote spawner arguments
    663      * @param peer non-null; peer credentials
    664      * @throws ZygoteSecurityException
    665      */
    666     private static void applyRlimitSecurityPolicy(
    667             Arguments args, Credentials peer)
    668             throws ZygoteSecurityException {
    669 
    670         int peerUid = peer.getUid();
    671 
    672         if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) {
    673             // All peers with UID other than root or SYSTEM_UID
    674             if (args.rlimits != null) {
    675                 throw new ZygoteSecurityException(
    676                         "This UID may not specify rlimits.");
    677             }
    678         }
    679     }
    680 
    681     /**
    682      * Applies zygote security policy per bug #1042973. A root peer may
    683      * spawn an instance with any capabilities. All other uids may spawn
    684      * instances with any of the capabilities in the peer's permitted set
    685      * but no more.
    686      *
    687      * @param args non-null; zygote spawner arguments
    688      * @param peer non-null; peer credentials
    689      * @throws ZygoteSecurityException
    690      */
    691     private static void applyCapabilitiesSecurityPolicy(
    692             Arguments args, Credentials peer)
    693             throws ZygoteSecurityException {
    694 
    695         if (args.permittedCapabilities == 0
    696                 && args.effectiveCapabilities == 0) {
    697             // nothing to check
    698             return;
    699         }
    700 
    701         if (peer.getUid() == 0) {
    702             // root may specify anything
    703             return;
    704         }
    705 
    706         long permittedCaps;
    707 
    708         try {
    709             permittedCaps = ZygoteInit.capgetPermitted(peer.getPid());
    710         } catch (IOException ex) {
    711             throw new ZygoteSecurityException(
    712                     "Error retrieving peer's capabilities.");
    713         }
    714 
    715         /*
    716          * Ensure that the client did not specify an effective set larger
    717          * than the permitted set. The kernel will enforce this too, but we
    718          * do it here to make the following check easier.
    719          */
    720         if (((~args.permittedCapabilities) & args.effectiveCapabilities) != 0) {
    721             throw new ZygoteSecurityException(
    722                     "Effective capabilities cannot be superset of "
    723                             + " permitted capabilities" );
    724         }
    725 
    726         /*
    727          * Ensure that the new permitted (and thus the new effective) set is
    728          * a subset of the peer process's permitted set
    729          */
    730 
    731         if (((~permittedCaps) & args.permittedCapabilities) != 0) {
    732             throw new ZygoteSecurityException(
    733                     "Peer specified unpermitted capabilities" );
    734         }
    735     }
    736 
    737     /**
    738      * Applies zygote security policy.
    739      * Based on the credentials of the process issuing a zygote command:
    740      * <ol>
    741      * <li> uid 0 (root) may specify --invoke-with to launch Zygote with a
    742      * wrapper command.
    743      * <li> Any other uid may not specify any invoke-with argument.
    744      * </ul>
    745      *
    746      * @param args non-null; zygote spawner arguments
    747      * @param peer non-null; peer credentials
    748      * @throws ZygoteSecurityException
    749      */
    750     private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer)
    751             throws ZygoteSecurityException {
    752         int peerUid = peer.getUid();
    753 
    754         if (args.invokeWith != null && peerUid != 0) {
    755             throw new ZygoteSecurityException("Peer is not permitted to specify "
    756                     + "an explicit invoke-with wrapper command");
    757         }
    758     }
    759 
    760     /**
    761      * Applies invoke-with system properties to the zygote arguments.
    762      *
    763      * @param parsedArgs non-null; zygote args
    764      */
    765     public static void applyInvokeWithSystemProperty(Arguments args) {
    766         if (args.invokeWith == null && args.niceName != null) {
    767             if (args.niceName != null) {
    768                 String property = "wrap." + args.niceName;
    769                 if (property.length() > 31) {
    770                     property = property.substring(0, 31);
    771                 }
    772                 args.invokeWith = SystemProperties.get(property);
    773                 if (args.invokeWith != null && args.invokeWith.length() == 0) {
    774                     args.invokeWith = null;
    775                 }
    776             }
    777         }
    778     }
    779 
    780     /**
    781      * Handles post-fork setup of child proc, closing sockets as appropriate,
    782      * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
    783      * if successful or returning if failed.
    784      *
    785      * @param parsedArgs non-null; zygote args
    786      * @param descriptors null-ok; new file descriptors for stdio if available.
    787      * @param pipeFd null-ok; pipe for communication back to Zygote.
    788      * @param newStderr null-ok; stream to use for stderr until stdio
    789      * is reopened.
    790      *
    791      * @throws ZygoteInit.MethodAndArgsCaller on success to
    792      * trampoline to code that invokes static main.
    793      */
    794     private void handleChildProc(Arguments parsedArgs,
    795             FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
    796             throws ZygoteInit.MethodAndArgsCaller {
    797 
    798         /*
    799          * Close the socket, unless we're in "peer wait" mode, in which
    800          * case it's used to track the liveness of this process.
    801          */
    802 
    803         if (parsedArgs.peerWait) {
    804             try {
    805                 ZygoteInit.setCloseOnExec(mSocket.getFileDescriptor(), true);
    806                 sPeerWaitSocket = mSocket;
    807             } catch (IOException ex) {
    808                 Log.e(TAG, "Zygote Child: error setting peer wait "
    809                         + "socket to be close-on-exec", ex);
    810             }
    811         } else {
    812             closeSocket();
    813             ZygoteInit.closeServerSocket();
    814         }
    815 
    816         if (descriptors != null) {
    817             try {
    818                 ZygoteInit.reopenStdio(descriptors[0],
    819                         descriptors[1], descriptors[2]);
    820 
    821                 for (FileDescriptor fd: descriptors) {
    822                     IoUtils.closeQuietly(fd);
    823                 }
    824                 newStderr = System.err;
    825             } catch (IOException ex) {
    826                 Log.e(TAG, "Error reopening stdio", ex);
    827             }
    828         }
    829 
    830         if (parsedArgs.niceName != null) {
    831             Process.setArgV0(parsedArgs.niceName);
    832         }
    833 
    834         if (parsedArgs.runtimeInit) {
    835             if (parsedArgs.invokeWith != null) {
    836                 WrapperInit.execApplication(parsedArgs.invokeWith,
    837                         parsedArgs.niceName, parsedArgs.targetSdkVersion,
    838                         pipeFd, parsedArgs.remainingArgs);
    839             } else {
    840                 RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
    841                         parsedArgs.remainingArgs);
    842             }
    843         } else {
    844             String className;
    845             try {
    846                 className = parsedArgs.remainingArgs[0];
    847             } catch (ArrayIndexOutOfBoundsException ex) {
    848                 logAndPrintError(newStderr,
    849                         "Missing required class name argument", null);
    850                 return;
    851             }
    852 
    853             String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];
    854             System.arraycopy(parsedArgs.remainingArgs, 1,
    855                     mainArgs, 0, mainArgs.length);
    856 
    857             if (parsedArgs.invokeWith != null) {
    858                 WrapperInit.execStandalone(parsedArgs.invokeWith,
    859                         parsedArgs.classpath, className, mainArgs);
    860             } else {
    861                 ClassLoader cloader;
    862                 if (parsedArgs.classpath != null) {
    863                     cloader = new PathClassLoader(parsedArgs.classpath,
    864                             ClassLoader.getSystemClassLoader());
    865                 } else {
    866                     cloader = ClassLoader.getSystemClassLoader();
    867                 }
    868 
    869                 try {
    870                     ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
    871                 } catch (RuntimeException ex) {
    872                     logAndPrintError(newStderr, "Error starting.", ex);
    873                 }
    874             }
    875         }
    876     }
    877 
    878     /**
    879      * Handles post-fork cleanup of parent proc
    880      *
    881      * @param pid != 0; pid of child if &gt; 0 or indication of failed fork
    882      * if &lt; 0;
    883      * @param descriptors null-ok; file descriptors for child's new stdio if
    884      * specified.
    885      * @param pipeFd null-ok; pipe for communication with child.
    886      * @param parsedArgs non-null; zygote args
    887      * @return true for "exit command loop" and false for "continue command
    888      * loop"
    889      */
    890     private boolean handleParentProc(int pid,
    891             FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {
    892 
    893         if (pid > 0) {
    894             setChildPgid(pid);
    895         }
    896 
    897         if (descriptors != null) {
    898             for (FileDescriptor fd: descriptors) {
    899                 IoUtils.closeQuietly(fd);
    900             }
    901         }
    902 
    903         boolean usingWrapper = false;
    904         if (pipeFd != null && pid > 0) {
    905             DataInputStream is = new DataInputStream(new FileInputStream(pipeFd));
    906             int innerPid = -1;
    907             try {
    908                 innerPid = is.readInt();
    909             } catch (IOException ex) {
    910                 Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
    911             } finally {
    912                 try {
    913                     is.close();
    914                 } catch (IOException ex) {
    915                 }
    916             }
    917 
    918             // Ensure that the pid reported by the wrapped process is either the
    919             // child process that we forked, or a descendant of it.
    920             if (innerPid > 0) {
    921                 int parentPid = innerPid;
    922                 while (parentPid > 0 && parentPid != pid) {
    923                     parentPid = Process.getParentPid(parentPid);
    924                 }
    925                 if (parentPid > 0) {
    926                     Log.i(TAG, "Wrapped process has pid " + innerPid);
    927                     pid = innerPid;
    928                     usingWrapper = true;
    929                 } else {
    930                     Log.w(TAG, "Wrapped process reported a pid that is not a child of "
    931                             + "the process that we forked: childPid=" + pid
    932                             + " innerPid=" + innerPid);
    933                 }
    934             }
    935         }
    936 
    937         try {
    938             mSocketOutStream.writeInt(pid);
    939             mSocketOutStream.writeBoolean(usingWrapper);
    940         } catch (IOException ex) {
    941             Log.e(TAG, "Error reading from command socket", ex);
    942             return true;
    943         }
    944 
    945         /*
    946          * If the peer wants to use the socket to wait on the
    947          * newly spawned process, then we're all done.
    948          */
    949         if (parsedArgs.peerWait) {
    950             try {
    951                 mSocket.close();
    952             } catch (IOException ex) {
    953                 Log.e(TAG, "Zygote: error closing sockets", ex);
    954             }
    955             return true;
    956         }
    957         return false;
    958     }
    959 
    960     private void setChildPgid(int pid) {
    961         // Try to move the new child into the peer's process group.
    962         try {
    963             ZygoteInit.setpgid(pid, ZygoteInit.getpgid(peer.getPid()));
    964         } catch (IOException ex) {
    965             // This exception is expected in the case where
    966             // the peer is not in our session
    967             // TODO get rid of this log message in the case where
    968             // getsid(0) != getsid(peer.getPid())
    969             Log.i(TAG, "Zygote: setpgid failed. This is "
    970                 + "normal if peer is not in our session");
    971         }
    972     }
    973 
    974     /**
    975      * Logs an error message and prints it to the specified stream, if
    976      * provided
    977      *
    978      * @param newStderr null-ok; a standard error stream
    979      * @param message non-null; error message
    980      * @param ex null-ok an exception
    981      */
    982     private static void logAndPrintError (PrintStream newStderr,
    983             String message, Throwable ex) {
    984         Log.e(TAG, message, ex);
    985         if (newStderr != null) {
    986             newStderr.println(message + (ex == null ? "" : ex));
    987         }
    988     }
    989 }
    990