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