ZygoteConnection.java revision 95b1048d390e79029978efd4654c05816722e17f
1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/* 2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Copyright (C) 2007 The Android Open Source Project 3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * 4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Licensed under the Apache License, Version 2.0 (the "License"); 5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * you may not use this file except in compliance with the License. 6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * You may obtain a copy of the License at 7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * 8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * http://www.apache.org/licenses/LICENSE-2.0 9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * 10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Unless required by applicable law or agreed to in writing, software 11026d1ce6fc5608190aa5fd48f51278c60515c093pbos@webrtc.org * distributed under the License is distributed on an "AS IS" BASIS, 12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * See the License for the specific language governing permissions and 143bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * limitations under the License. 15b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */ 16266fc69742dbcff7e1f46e2960470feb1a98650candrew@webrtc.org 17266fc69742dbcff7e1f46e2960470feb1a98650candrew@webrtc.orgpackage com.android.internal.os; 18b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 19b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport android.net.Credentials; 20b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport android.net.LocalSocket; 217012d2b0a89b5697dea51f17643bd40f2552a601mikhal@webrtc.orgimport android.os.Process; 227012d2b0a89b5697dea51f17643bd40f2552a601mikhal@webrtc.orgimport android.os.SELinux; 23b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport android.os.SystemProperties; 24b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport android.system.ErrnoException; 25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport android.system.Os; 26b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport android.util.Log; 27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport dalvik.system.PathClassLoader; 28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport java.io.BufferedReader; 29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport java.io.DataInputStream; 30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport java.io.DataOutputStream; 31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport java.io.FileDescriptor; 32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport java.io.FileInputStream; 33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport java.io.FileOutputStream; 34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport java.io.IOException; 35b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport java.io.InputStreamReader; 36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport java.io.PrintStream; 37b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport java.nio.charset.StandardCharsets; 38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport java.util.ArrayList; 39b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport libcore.io.IoUtils; 40b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport android.os.SystemClock; 41b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgimport android.util.Slog; 42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/** 44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * A connection that can make spawn requests. 45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */ 46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgclass ZygoteConnection { 47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org private static final String TAG = "Zygote"; 48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org /** a prototype instance for a future List.toArray() */ 50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org private static final int[][] intArray2d = new int[0][0]; 51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org /** 53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * {@link android.net.LocalSocket#setSoTimeout} value for connections. 54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Effectively, the amount of time a requestor has between the start of 55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * the request and the completed request. The select-loop mode Zygote 56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * doesn't have the logic to return to the select loop in the middle of 57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * a request, so we need to time out here to avoid being denial-of-serviced. 58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */ 59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org private static final int CONNECTION_TIMEOUT_MILLIS = 1000; 60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org /** max number of arguments that a connection can specify */ 62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org private static final int MAX_ZYGOTE_ARGC = 1024; 63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 647012d2b0a89b5697dea51f17643bd40f2552a601mikhal@webrtc.org /** 657012d2b0a89b5697dea51f17643bd40f2552a601mikhal@webrtc.org * The command socket. 667012d2b0a89b5697dea51f17643bd40f2552a601mikhal@webrtc.org * 677012d2b0a89b5697dea51f17643bd40f2552a601mikhal@webrtc.org * mSocket is retained in the child process in "peer wait" mode, so 687012d2b0a89b5697dea51f17643bd40f2552a601mikhal@webrtc.org * that it closes when the child process terminates. In other cases, 69b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * it is closed in the peer. 70b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */ 71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org private final LocalSocket mSocket; 72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org private final DataOutputStream mSocketOutStream; 73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org private final BufferedReader mSocketReader; 74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org private final Credentials peer; 75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org private final String peerSecurityContext; 76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org private final String abiList; 77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org /** 79b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Constructs instance from connected socket. 80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * 81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * @param socket non-null; connected socket 82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * @param abiList non-null; a list of ABIs this zygote supports. 83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * @throws IOException 84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */ 85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ZygoteConnection(LocalSocket socket, String abiList) throws IOException { 86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org mSocket = socket; 87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org this.abiList = abiList; 88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org mSocketOutStream 90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org = new DataOutputStream(socket.getOutputStream()); 91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org mSocketReader = new BufferedReader( 93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org new InputStreamReader(socket.getInputStream()), 256); 94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS); 96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org try { 98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org peer = mSocket.getPeerCredentials(); 99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } catch (IOException ex) { 100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org Log.e(TAG, "Cannot read peer credentials", ex); 101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org throw ex; 102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 1033bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 1043bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org peerSecurityContext = SELinux.getPeerContext(mSocket.getFileDescriptor()); 1053bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org } 1063bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 1073bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org /** 1083bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * Temporary hack: check time since start time and log if over a fixed threshold. 1093bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * 1103bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org */ 1113bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org private void checkTime(long startTime, String where) { 1123bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org long now = SystemClock.elapsedRealtime(); 1133bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org if ((now-startTime) > 1000) { 1143bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org // If we are taking more than a second, log about it. 1153bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org Slog.w(TAG, "Slow operation: " + (now-startTime) + "ms so far, now at " + where); 1163bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org } 1173bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org } 1183bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 1193bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org /** 1203bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * Returns the file descriptor of the associated socket. 1213bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * 1223bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * @return null-ok; file descriptor 1233bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org */ 1243bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org FileDescriptor getFileDescriptor() { 1253bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org return mSocket.getFileDescriptor(); 1263bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org } 1273bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 1283bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org /** 1293bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * Reads one start command from the command socket. If successful, 1303bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * a child is forked and a {@link ZygoteInit.MethodAndArgsCaller} 1313bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * exception is thrown in that child while in the parent process, 1323bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * the method returns normally. On failure, the child is not 1333bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * spawned and messages are printed to the log and stderr. Returns 1343bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * a boolean status value indicating whether an end-of-file on the command 1353bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * socket has been encountered. 1363bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * 1373bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * @return false if command socket should continue to be read from, or 1383bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * true if an end-of-file has been encountered. 1393bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main() 1403bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * method in child process 1413bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org */ 1423bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { 1433bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 1443bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org String args[]; 1453bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org Arguments parsedArgs = null; 1463bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org FileDescriptor[] descriptors; 1473bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 1483bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org long startTime = SystemClock.elapsedRealtime(); 1493bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 1503bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org try { 1513bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org args = readArgumentList(); 1523bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org descriptors = mSocket.getAncillaryFileDescriptors(); 1533bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org } catch (IOException ex) { 154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org Log.w(TAG, "IOException on command socket " + ex.getMessage()); 155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org closeSocket(); 156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return true; 157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org checkTime(startTime, "zygoteConnection.runOnce: readArgumentList"); 160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (args == null) { 161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // EOF reached. 162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org closeSocket(); 163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return true; 164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org /** the stderr of the most recent request, if avail */ 167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org PrintStream newStderr = null; 168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (descriptors != null && descriptors.length >= 3) { 170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org newStderr = new PrintStream( 171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org new FileOutputStream(descriptors[2])); 172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int pid = -1; 175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org FileDescriptor childPipeFd = null; 176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org FileDescriptor serverPipeFd = null; 177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org try { 179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org parsedArgs = new Arguments(args); 180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (parsedArgs.abiListQuery) { 182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return handleAbiListQuery(); 183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) { 186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org throw new ZygoteSecurityException("Client may not specify capabilities: " + 187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) + 188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities)); 189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext); 193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext); 194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext); 195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext); 196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org checkTime(startTime, "zygoteConnection.runOnce: apply security policies"); 198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org applyDebuggerSystemProperty(parsedArgs); 200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org applyInvokeWithSystemProperty(parsedArgs); 201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org checkTime(startTime, "zygoteConnection.runOnce: apply security policies"); 203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int[][] rlimits = null; 205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (parsedArgs.rlimits != null) { 207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org rlimits = parsedArgs.rlimits.toArray(intArray2d); 208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) { 211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org FileDescriptor[] pipeFds = Os.pipe(); 212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org childPipeFd = pipeFds[1]; 213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org serverPipeFd = pipeFds[0]; 214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ZygoteInit.setCloseOnExec(serverPipeFd, true); 215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org /** 218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * In order to avoid leaking descriptors to the Zygote child, 219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * the native code must close the two Zygote socket descriptors 220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * in the child process before it switches from Zygote-root to 221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * the UID and privileges of the application being launched. 222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * 223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * In order to avoid "bad file descriptor" errors when the 224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * two LocalSocket objects are closed, the Posix file 225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * descriptors are released via a dup2() call which closes 226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * the socket and substitutes an open descriptor to /dev/null. 227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */ 228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int [] fdsToClose = { -1, -1 }; 230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org FileDescriptor fd = mSocket.getFileDescriptor(); 232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org if (fd != null) { 234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org fdsToClose[0] = fd.getInt$(); 2353bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org } 2365be3165fad82f4b8b5d986fa567dde21584a13f8mikhal@webrtc.org 2375be3165fad82f4b8b5d986fa567dde21584a13f8mikhal@webrtc.org fd = ZygoteInit.getServerSocketFileDescriptor(); 2385be3165fad82f4b8b5d986fa567dde21584a13f8mikhal@webrtc.org 2395be3165fad82f4b8b5d986fa567dde21584a13f8mikhal@webrtc.org if (fd != null) { 2405be3165fad82f4b8b5d986fa567dde21584a13f8mikhal@webrtc.org fdsToClose[1] = fd.getInt$(); 2415be3165fad82f4b8b5d986fa567dde21584a13f8mikhal@webrtc.org } 2425be3165fad82f4b8b5d986fa567dde21584a13f8mikhal@webrtc.org 2435be3165fad82f4b8b5d986fa567dde21584a13f8mikhal@webrtc.org fd = null; 244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2453bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org checkTime(startTime, "zygoteConnection.runOnce: preForkAndSpecialize"); 2463bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, 2473bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, 2483bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet, 2493bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org parsedArgs.appDataDir); 2503bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org checkTime(startTime, "zygoteConnection.runOnce: postForkAndSpecialize"); 251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } catch (IOException ex) { 252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logAndPrintError(newStderr, "Exception creating pipe", ex); 2535be3165fad82f4b8b5d986fa567dde21584a13f8mikhal@webrtc.org } catch (ErrnoException ex) { 254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logAndPrintError(newStderr, "Exception creating pipe", ex); 255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } catch (IllegalArgumentException ex) { 256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org logAndPrintError(newStderr, "Invalid zygote arguments", ex); 257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } catch (ZygoteSecurityException ex) { 2583bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org logAndPrintError(newStderr, 259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "Zygote security policy prevents request: ", ex); 260b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2613bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 2623bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org try { 2633bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org if (pid == 0) { 2643bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org // in child 2653bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org IoUtils.closeQuietly(serverPipeFd); 2663bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org serverPipeFd = null; 267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); 2683bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // should never get here, the child is expected to either 270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org // throw ZygoteInit.MethodAndArgsCaller or exec(). 271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return true; 2723bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org } else { 2733bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org // in parent...pid of < 0 means failure 274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org IoUtils.closeQuietly(childPipeFd); 275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org childPipeFd = null; 276b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); 2773bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org } 2783bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org } finally { 2793bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org IoUtils.closeQuietly(childPipeFd); 2803bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org IoUtils.closeQuietly(serverPipeFd); 2813bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org } 2823bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org } 283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 2843bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org private boolean handleAbiListQuery() { 285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org try { 286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org final byte[] abiListBytes = abiList.getBytes(StandardCharsets.US_ASCII); 287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org mSocketOutStream.writeInt(abiListBytes.length); 2883bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org mSocketOutStream.write(abiListBytes); 2893bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org return false; 290b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } catch (IOException ioe) { 2913bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org Log.e(TAG, "Error writing to command socket", ioe); 2923bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org return true; 293b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org } 2943bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org } 2953bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 2963bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org /** 2973bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * Closes socket associated with this connection. 2983bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org */ 2993bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org void closeSocket() { 3003bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org try { 3013bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org mSocket.close(); 3023bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org } catch (IOException ex) { 3033bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org Log.e(TAG, "Exception while closing command " 3043bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org + "socket in parent", ex); 3053bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org } 3063bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org } 307b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 308b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org /** 3093bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * Handles argument parsing for args related to the zygote spawner. 3103bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * 311b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * Current recognized args: 3123bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * <ul> 3133bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * <li> --setuid=<i>uid of child process, defaults to 0</i> 314b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * <li> --setgid=<i>gid of child process, defaults to 0</i> 315b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * <li> --setgroups=<i>comma-separated list of supplimentary gid's</i> 316b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * <li> --capabilities=<i>a pair of comma-separated integer strings 3173bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * indicating Linux capabilities(2) set for child. The first string 3183bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * represents the <code>permitted</code> set, and the second the 3193bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * <code>effective</code> set. Precede each with 0 or 3203bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * 0x for octal or hexidecimal value. If unspecified, both default to 0. 3213bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * This parameter is only applied if the uid of the new process will 3223bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * be non-0. </i> 3233bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * <li> --rlimit=r,c,m<i>tuple of values for setrlimit() call. 3243bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * <code>r</code> is the resource, <code>c</code> and <code>m</code> 3253bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * are the settings for current and max value.</i> 3263bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * <li> --classpath=<i>colon-separated classpath</i> indicates 3273bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * that the specified class (which must b first non-flag argument) should 3283bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * be loaded from jar files in the specified classpath. Incompatible with 3293bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * --runtime-init 330b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * <li> --runtime-init indicates that the remaining arg list should 331b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * be handed off to com.android.internal.os.RuntimeInit, rather than 332b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * processed directly 3333bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * Android runtime startup (eg, Binder initialization) is also eschewed. 3343bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * <li> --nice-name=<i>nice name to appear in ps</i> 335b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * <li> If <code>--runtime-init</code> is present: 336b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * [--] <args for RuntimeInit > 3373bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * <li> If <code>--runtime-init</code> is absent: 3383bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * [--] <classname> [args...] 339b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org * <li> --instruction-set=<i>instruction-set-string</i> which instruction set to use/emulate. 3403bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * </ul> 341b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */ 3423bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org static class Arguments { 3433bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org /** from --setuid */ 3443bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org int uid = 0; 3453bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org boolean uidSpecified; 3463bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 3473bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org /** from --setgid */ 3483bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org int gid = 0; 3493bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org boolean gidSpecified; 3503bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 3513bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org /** from --setgroups */ 3523bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org int[] gids; 3533bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 3543bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org /** 3553bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org * From --enable-debugger, --enable-checkjni, --enable-assert, 3565600f6e86d3994726249fd1c77377c1d8534f107phoglund@webrtc.org * --enable-safemode, and --enable-jni-logging. 357b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */ 358ecf6f810b59a3f0e51805cc656a1cffadc8a6dbbphoglund@webrtc.org int debugFlags; 359b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org 3603bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org /** From --mount-external */ 361b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int mountExternal = Zygote.MOUNT_EXTERNAL_NONE; 3623bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 3633bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org /** from --target-sdk-version. */ 364b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org int targetSdkVersion; 365b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org boolean targetSdkVersionSpecified; 3663bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 3673bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org /** from --classpath */ 368b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org String classpath; 3693bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 370b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org /** from --runtime-init */ 3713bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org boolean runtimeInit; 3723bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 3733bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org /** from --nice-name */ 3743bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org String niceName; 3753bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 3763bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org /** from --capabilities */ 3773bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org boolean capabilitiesSpecified; 3783bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org long permittedCapabilities; 3793bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org long effectiveCapabilities; 3803bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 3813bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org /** from --seinfo */ 3823bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org boolean seInfoSpecified; 3833bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org String seInfo; 3843bbed74cdcf1f27ce82104ce645ec0dcdd36902dmikhal@webrtc.org 385b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org /** from all --rlimit=r,c,m */ 386b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org ArrayList<int[]> rlimits; 387 388 /** from --invoke-with */ 389 String invokeWith; 390 391 /** 392 * Any args after and including the first non-option arg 393 * (or after a '--') 394 */ 395 String remainingArgs[]; 396 397 /** 398 * Whether the current arguments constitute an ABI list query. 399 */ 400 boolean abiListQuery; 401 402 /** 403 * The instruction set to use, or null when not important. 404 */ 405 String instructionSet; 406 407 /** 408 * The app data directory. May be null, e.g., for the system server. Note that this might 409 * not be reliable in the case of process-sharing apps. 410 */ 411 String appDataDir; 412 413 /** 414 * Constructs instance and parses args 415 * @param args zygote command-line args 416 * @throws IllegalArgumentException 417 */ 418 Arguments(String args[]) throws IllegalArgumentException { 419 parseArgs(args); 420 } 421 422 /** 423 * Parses the commandline arguments intended for the Zygote spawner 424 * (such as "--setuid=" and "--setgid=") and creates an array 425 * containing the remaining args. 426 * 427 * Per security review bug #1112214, duplicate args are disallowed in 428 * critical cases to make injection harder. 429 */ 430 private void parseArgs(String args[]) 431 throws IllegalArgumentException { 432 int curArg = 0; 433 434 for ( /* curArg */ ; curArg < args.length; curArg++) { 435 String arg = args[curArg]; 436 437 if (arg.equals("--")) { 438 curArg++; 439 break; 440 } else if (arg.startsWith("--setuid=")) { 441 if (uidSpecified) { 442 throw new IllegalArgumentException( 443 "Duplicate arg specified"); 444 } 445 uidSpecified = true; 446 uid = Integer.parseInt( 447 arg.substring(arg.indexOf('=') + 1)); 448 } else if (arg.startsWith("--setgid=")) { 449 if (gidSpecified) { 450 throw new IllegalArgumentException( 451 "Duplicate arg specified"); 452 } 453 gidSpecified = true; 454 gid = Integer.parseInt( 455 arg.substring(arg.indexOf('=') + 1)); 456 } else if (arg.startsWith("--target-sdk-version=")) { 457 if (targetSdkVersionSpecified) { 458 throw new IllegalArgumentException( 459 "Duplicate target-sdk-version specified"); 460 } 461 targetSdkVersionSpecified = true; 462 targetSdkVersion = Integer.parseInt( 463 arg.substring(arg.indexOf('=') + 1)); 464 } else if (arg.equals("--enable-debugger")) { 465 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER; 466 } else if (arg.equals("--enable-safemode")) { 467 debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE; 468 } else if (arg.equals("--enable-checkjni")) { 469 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI; 470 } else if (arg.equals("--enable-jni-logging")) { 471 debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING; 472 } else if (arg.equals("--enable-assert")) { 473 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT; 474 } else if (arg.equals("--runtime-init")) { 475 runtimeInit = true; 476 } else if (arg.startsWith("--seinfo=")) { 477 if (seInfoSpecified) { 478 throw new IllegalArgumentException( 479 "Duplicate arg specified"); 480 } 481 seInfoSpecified = true; 482 seInfo = arg.substring(arg.indexOf('=') + 1); 483 } else if (arg.startsWith("--capabilities=")) { 484 if (capabilitiesSpecified) { 485 throw new IllegalArgumentException( 486 "Duplicate arg specified"); 487 } 488 capabilitiesSpecified = true; 489 String capString = arg.substring(arg.indexOf('=')+1); 490 491 String[] capStrings = capString.split(",", 2); 492 493 if (capStrings.length == 1) { 494 effectiveCapabilities = Long.decode(capStrings[0]); 495 permittedCapabilities = effectiveCapabilities; 496 } else { 497 permittedCapabilities = Long.decode(capStrings[0]); 498 effectiveCapabilities = Long.decode(capStrings[1]); 499 } 500 } else if (arg.startsWith("--rlimit=")) { 501 // Duplicate --rlimit arguments are specifically allowed. 502 String[] limitStrings 503 = arg.substring(arg.indexOf('=')+1).split(","); 504 505 if (limitStrings.length != 3) { 506 throw new IllegalArgumentException( 507 "--rlimit= should have 3 comma-delimited ints"); 508 } 509 int[] rlimitTuple = new int[limitStrings.length]; 510 511 for(int i=0; i < limitStrings.length; i++) { 512 rlimitTuple[i] = Integer.parseInt(limitStrings[i]); 513 } 514 515 if (rlimits == null) { 516 rlimits = new ArrayList(); 517 } 518 519 rlimits.add(rlimitTuple); 520 } else if (arg.equals("-classpath")) { 521 if (classpath != null) { 522 throw new IllegalArgumentException( 523 "Duplicate arg specified"); 524 } 525 try { 526 classpath = args[++curArg]; 527 } catch (IndexOutOfBoundsException ex) { 528 throw new IllegalArgumentException( 529 "-classpath requires argument"); 530 } 531 } else if (arg.startsWith("--setgroups=")) { 532 if (gids != null) { 533 throw new IllegalArgumentException( 534 "Duplicate arg specified"); 535 } 536 537 String[] params 538 = arg.substring(arg.indexOf('=') + 1).split(","); 539 540 gids = new int[params.length]; 541 542 for (int i = params.length - 1; i >= 0 ; i--) { 543 gids[i] = Integer.parseInt(params[i]); 544 } 545 } else if (arg.equals("--invoke-with")) { 546 if (invokeWith != null) { 547 throw new IllegalArgumentException( 548 "Duplicate arg specified"); 549 } 550 try { 551 invokeWith = args[++curArg]; 552 } catch (IndexOutOfBoundsException ex) { 553 throw new IllegalArgumentException( 554 "--invoke-with requires argument"); 555 } 556 } else if (arg.startsWith("--nice-name=")) { 557 if (niceName != null) { 558 throw new IllegalArgumentException( 559 "Duplicate arg specified"); 560 } 561 niceName = arg.substring(arg.indexOf('=') + 1); 562 } else if (arg.equals("--mount-external-multiuser")) { 563 mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER; 564 } else if (arg.equals("--mount-external-multiuser-all")) { 565 mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL; 566 } else if (arg.equals("--query-abi-list")) { 567 abiListQuery = true; 568 } else if (arg.startsWith("--instruction-set=")) { 569 instructionSet = arg.substring(arg.indexOf('=') + 1); 570 } else if (arg.startsWith("--app-data-dir=")) { 571 appDataDir = arg.substring(arg.indexOf('=') + 1); 572 } else { 573 break; 574 } 575 } 576 577 if (runtimeInit && classpath != null) { 578 throw new IllegalArgumentException( 579 "--runtime-init and -classpath are incompatible"); 580 } 581 582 remainingArgs = new String[args.length - curArg]; 583 584 System.arraycopy(args, curArg, remainingArgs, 0, 585 remainingArgs.length); 586 } 587 } 588 589 /** 590 * Reads an argument list from the command socket/ 591 * @return Argument list or null if EOF is reached 592 * @throws IOException passed straight through 593 */ 594 private String[] readArgumentList() 595 throws IOException { 596 597 /** 598 * See android.os.Process.zygoteSendArgsAndGetPid() 599 * Presently the wire format to the zygote process is: 600 * a) a count of arguments (argc, in essence) 601 * b) a number of newline-separated argument strings equal to count 602 * 603 * After the zygote process reads these it will write the pid of 604 * the child or -1 on failure. 605 */ 606 607 int argc; 608 609 try { 610 String s = mSocketReader.readLine(); 611 612 if (s == null) { 613 // EOF reached. 614 return null; 615 } 616 argc = Integer.parseInt(s); 617 } catch (NumberFormatException ex) { 618 Log.e(TAG, "invalid Zygote wire format: non-int at argc"); 619 throw new IOException("invalid wire format"); 620 } 621 622 // See bug 1092107: large argc can be used for a DOS attack 623 if (argc > MAX_ZYGOTE_ARGC) { 624 throw new IOException("max arg count exceeded"); 625 } 626 627 String[] result = new String[argc]; 628 for (int i = 0; i < argc; i++) { 629 result[i] = mSocketReader.readLine(); 630 if (result[i] == null) { 631 // We got an unexpected EOF. 632 throw new IOException("truncated request"); 633 } 634 } 635 636 return result; 637 } 638 639 /** 640 * Applies zygote security policy per bugs #875058 and #1082165. 641 * Based on the credentials of the process issuing a zygote command: 642 * <ol> 643 * <li> uid 0 (root) may specify any uid, gid, and setgroups() list 644 * <li> uid 1000 (Process.SYSTEM_UID) may specify any uid > 1000 in normal 645 * operation. It may also specify any gid and setgroups() list it chooses. 646 * In factory test mode, it may specify any UID. 647 * <li> Any other uid may not specify any uid, gid, or setgroups list. The 648 * uid and gid will be inherited from the requesting process. 649 * </ul> 650 * 651 * @param args non-null; zygote spawner arguments 652 * @param peer non-null; peer credentials 653 * @throws ZygoteSecurityException 654 */ 655 private static void applyUidSecurityPolicy(Arguments args, Credentials peer, 656 String peerSecurityContext) 657 throws ZygoteSecurityException { 658 659 int peerUid = peer.getUid(); 660 661 if (peerUid == 0) { 662 // Root can do what it wants 663 } else if (peerUid == Process.SYSTEM_UID ) { 664 // System UID is restricted, except in factory test mode 665 String factoryTest = SystemProperties.get("ro.factorytest"); 666 boolean uidRestricted; 667 668 /* In normal operation, SYSTEM_UID can only specify a restricted 669 * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid. 670 */ 671 uidRestricted 672 = !(factoryTest.equals("1") || factoryTest.equals("2")); 673 674 if (uidRestricted 675 && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) { 676 throw new ZygoteSecurityException( 677 "System UID may not launch process with UID < " 678 + Process.SYSTEM_UID); 679 } 680 } else { 681 // Everything else 682 if (args.uidSpecified || args.gidSpecified 683 || args.gids != null) { 684 throw new ZygoteSecurityException( 685 "App UIDs may not specify uid's or gid's"); 686 } 687 } 688 689 if (args.uidSpecified || args.gidSpecified || args.gids != null) { 690 boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, 691 peerSecurityContext, 692 "zygote", 693 "specifyids"); 694 if (!allowed) { 695 throw new ZygoteSecurityException( 696 "Peer may not specify uid's or gid's"); 697 } 698 } 699 700 // If not otherwise specified, uid and gid are inherited from peer 701 if (!args.uidSpecified) { 702 args.uid = peer.getUid(); 703 args.uidSpecified = true; 704 } 705 if (!args.gidSpecified) { 706 args.gid = peer.getGid(); 707 args.gidSpecified = true; 708 } 709 } 710 711 712 /** 713 * Applies debugger system properties to the zygote arguments. 714 * 715 * If "ro.debuggable" is "1", all apps are debuggable. Otherwise, 716 * the debugger state is specified via the "--enable-debugger" flag 717 * in the spawn request. 718 * 719 * @param args non-null; zygote spawner args 720 */ 721 public static void applyDebuggerSystemProperty(Arguments args) { 722 if ("1".equals(SystemProperties.get("ro.debuggable"))) { 723 args.debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER; 724 } 725 } 726 727 /** 728 * Applies zygote security policy per bug #1042973. Based on the credentials 729 * of the process issuing a zygote command: 730 * <ol> 731 * <li> peers of uid 0 (root) and uid 1000 (Process.SYSTEM_UID) 732 * may specify any rlimits. 733 * <li> All other uids may not specify rlimits. 734 * </ul> 735 * @param args non-null; zygote spawner arguments 736 * @param peer non-null; peer credentials 737 * @throws ZygoteSecurityException 738 */ 739 private static void applyRlimitSecurityPolicy( 740 Arguments args, Credentials peer, String peerSecurityContext) 741 throws ZygoteSecurityException { 742 743 int peerUid = peer.getUid(); 744 745 if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) { 746 // All peers with UID other than root or SYSTEM_UID 747 if (args.rlimits != null) { 748 throw new ZygoteSecurityException( 749 "This UID may not specify rlimits."); 750 } 751 } 752 753 if (args.rlimits != null) { 754 boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, 755 peerSecurityContext, 756 "zygote", 757 "specifyrlimits"); 758 if (!allowed) { 759 throw new ZygoteSecurityException( 760 "Peer may not specify rlimits"); 761 } 762 } 763 } 764 765 /** 766 * Applies zygote security policy. 767 * Based on the credentials of the process issuing a zygote command: 768 * <ol> 769 * <li> uid 0 (root) may specify --invoke-with to launch Zygote with a 770 * wrapper command. 771 * <li> Any other uid may not specify any invoke-with argument. 772 * </ul> 773 * 774 * @param args non-null; zygote spawner arguments 775 * @param peer non-null; peer credentials 776 * @throws ZygoteSecurityException 777 */ 778 private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer, 779 String peerSecurityContext) 780 throws ZygoteSecurityException { 781 int peerUid = peer.getUid(); 782 783 if (args.invokeWith != null && peerUid != 0) { 784 throw new ZygoteSecurityException("Peer is not permitted to specify " 785 + "an explicit invoke-with wrapper command"); 786 } 787 788 if (args.invokeWith != null) { 789 boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, 790 peerSecurityContext, 791 "zygote", 792 "specifyinvokewith"); 793 if (!allowed) { 794 throw new ZygoteSecurityException("Peer is not permitted to specify " 795 + "an explicit invoke-with wrapper command"); 796 } 797 } 798 } 799 800 /** 801 * Applies zygote security policy for SELinux information. 802 * 803 * @param args non-null; zygote spawner arguments 804 * @param peer non-null; peer credentials 805 * @throws ZygoteSecurityException 806 */ 807 private static void applyseInfoSecurityPolicy( 808 Arguments args, Credentials peer, String peerSecurityContext) 809 throws ZygoteSecurityException { 810 int peerUid = peer.getUid(); 811 812 if (args.seInfo == null) { 813 // nothing to check 814 return; 815 } 816 817 if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) { 818 // All peers with UID other than root or SYSTEM_UID 819 throw new ZygoteSecurityException( 820 "This UID may not specify SELinux info."); 821 } 822 823 boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, 824 peerSecurityContext, 825 "zygote", 826 "specifyseinfo"); 827 if (!allowed) { 828 throw new ZygoteSecurityException( 829 "Peer may not specify SELinux info"); 830 } 831 832 return; 833 } 834 835 /** 836 * Applies invoke-with system properties to the zygote arguments. 837 * 838 * @param args non-null; zygote args 839 */ 840 public static void applyInvokeWithSystemProperty(Arguments args) { 841 if (args.invokeWith == null && args.niceName != null) { 842 if (args.niceName != null) { 843 String property = "wrap." + args.niceName; 844 if (property.length() > 31) { 845 // Avoid creating an illegal property name when truncating. 846 if (property.charAt(30) != '.') { 847 property = property.substring(0, 31); 848 } else { 849 property = property.substring(0, 30); 850 } 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 /** 879 * By the time we get here, the native code has closed the two actual Zygote 880 * socket connections, and substituted /dev/null in their place. The LocalSocket 881 * objects still need to be closed properly. 882 */ 883 884 closeSocket(); 885 ZygoteInit.closeServerSocket(); 886 887 if (descriptors != null) { 888 try { 889 ZygoteInit.reopenStdio(descriptors[0], 890 descriptors[1], descriptors[2]); 891 892 for (FileDescriptor fd: descriptors) { 893 IoUtils.closeQuietly(fd); 894 } 895 newStderr = System.err; 896 } catch (IOException ex) { 897 Log.e(TAG, "Error reopening stdio", ex); 898 } 899 } 900 901 if (parsedArgs.niceName != null) { 902 Process.setArgV0(parsedArgs.niceName); 903 } 904 905 if (parsedArgs.runtimeInit) { 906 if (parsedArgs.invokeWith != null) { 907 WrapperInit.execApplication(parsedArgs.invokeWith, 908 parsedArgs.niceName, parsedArgs.targetSdkVersion, 909 pipeFd, parsedArgs.remainingArgs); 910 } else { 911 RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, 912 parsedArgs.remainingArgs, null /* classLoader */); 913 } 914 } else { 915 String className; 916 try { 917 className = parsedArgs.remainingArgs[0]; 918 } catch (ArrayIndexOutOfBoundsException ex) { 919 logAndPrintError(newStderr, 920 "Missing required class name argument", null); 921 return; 922 } 923 924 String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1]; 925 System.arraycopy(parsedArgs.remainingArgs, 1, 926 mainArgs, 0, mainArgs.length); 927 928 if (parsedArgs.invokeWith != null) { 929 WrapperInit.execStandalone(parsedArgs.invokeWith, 930 parsedArgs.classpath, className, mainArgs); 931 } else { 932 ClassLoader cloader; 933 if (parsedArgs.classpath != null) { 934 cloader = new PathClassLoader(parsedArgs.classpath, 935 ClassLoader.getSystemClassLoader()); 936 } else { 937 cloader = ClassLoader.getSystemClassLoader(); 938 } 939 940 try { 941 ZygoteInit.invokeStaticMain(cloader, className, mainArgs); 942 } catch (RuntimeException ex) { 943 logAndPrintError(newStderr, "Error starting.", ex); 944 } 945 } 946 } 947 } 948 949 /** 950 * Handles post-fork cleanup of parent proc 951 * 952 * @param pid != 0; pid of child if > 0 or indication of failed fork 953 * if < 0; 954 * @param descriptors null-ok; file descriptors for child's new stdio if 955 * specified. 956 * @param pipeFd null-ok; pipe for communication with child. 957 * @param parsedArgs non-null; zygote args 958 * @return true for "exit command loop" and false for "continue command 959 * loop" 960 */ 961 private boolean handleParentProc(int pid, 962 FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) { 963 964 if (pid > 0) { 965 setChildPgid(pid); 966 } 967 968 if (descriptors != null) { 969 for (FileDescriptor fd: descriptors) { 970 IoUtils.closeQuietly(fd); 971 } 972 } 973 974 boolean usingWrapper = false; 975 if (pipeFd != null && pid > 0) { 976 DataInputStream is = new DataInputStream(new FileInputStream(pipeFd)); 977 int innerPid = -1; 978 try { 979 innerPid = is.readInt(); 980 } catch (IOException ex) { 981 Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex); 982 } finally { 983 try { 984 is.close(); 985 } catch (IOException ex) { 986 } 987 } 988 989 // Ensure that the pid reported by the wrapped process is either the 990 // child process that we forked, or a descendant of it. 991 if (innerPid > 0) { 992 int parentPid = innerPid; 993 while (parentPid > 0 && parentPid != pid) { 994 parentPid = Process.getParentPid(parentPid); 995 } 996 if (parentPid > 0) { 997 Log.i(TAG, "Wrapped process has pid " + innerPid); 998 pid = innerPid; 999 usingWrapper = true; 1000 } else { 1001 Log.w(TAG, "Wrapped process reported a pid that is not a child of " 1002 + "the process that we forked: childPid=" + pid 1003 + " innerPid=" + innerPid); 1004 } 1005 } 1006 } 1007 1008 try { 1009 mSocketOutStream.writeInt(pid); 1010 mSocketOutStream.writeBoolean(usingWrapper); 1011 } catch (IOException ex) { 1012 Log.e(TAG, "Error writing to command socket", ex); 1013 return true; 1014 } 1015 1016 return false; 1017 } 1018 1019 private void setChildPgid(int pid) { 1020 // Try to move the new child into the peer's process group. 1021 try { 1022 ZygoteInit.setpgid(pid, ZygoteInit.getpgid(peer.getPid())); 1023 } catch (IOException ex) { 1024 // This exception is expected in the case where 1025 // the peer is not in our session 1026 // TODO get rid of this log message in the case where 1027 // getsid(0) != getsid(peer.getPid()) 1028 Log.i(TAG, "Zygote: setpgid failed. This is " 1029 + "normal if peer is not in our session"); 1030 } 1031 } 1032 1033 /** 1034 * Logs an error message and prints it to the specified stream, if 1035 * provided 1036 * 1037 * @param newStderr null-ok; a standard error stream 1038 * @param message non-null; error message 1039 * @param ex null-ok an exception 1040 */ 1041 private static void logAndPrintError (PrintStream newStderr, 1042 String message, Throwable ex) { 1043 Log.e(TAG, message, ex); 1044 if (newStderr != null) { 1045 newStderr.println(message + (ex == null ? "" : ex)); 1046 } 1047 } 1048} 1049