blob: ec80303f714a8427a62bd29703a5b91708c9ad4f [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package com.android.internal.os;
18
Narayan Kamath6ac7e672015-01-16 16:26:54 +000019import static android.system.OsConstants.F_SETFD;
Elliott Hughes3fe59512014-12-12 14:07:34 -080020import static android.system.OsConstants.O_CLOEXEC;
Elliott Hughesdac83f52014-12-15 11:00:25 -080021import static android.system.OsConstants.STDERR_FILENO;
22import static android.system.OsConstants.STDIN_FILENO;
23import static android.system.OsConstants.STDOUT_FILENO;
Elliott Hughes3fe59512014-12-12 14:07:34 -080024
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.net.Credentials;
26import android.net.LocalSocket;
27import android.os.Process;
Jeff Sharkey5b1ada22012-08-14 18:47:09 -070028import android.os.SELinux;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.os.SystemProperties;
Narayan Kamathfbb32f62015-06-12 15:34:35 +010030import android.os.Trace;
Elliott Hughes860c5912014-04-28 19:19:13 -070031import android.system.ErrnoException;
32import android.system.Os;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.util.Log;
Narayan Kamath37ad4b02015-01-19 16:05:24 +000034import dalvik.system.VMRuntime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import java.io.BufferedReader;
Jeff Brownebed7d62011-05-16 17:08:42 -070036import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import java.io.DataOutputStream;
38import java.io.FileDescriptor;
Jeff Brownebed7d62011-05-16 17:08:42 -070039import java.io.FileInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import java.io.FileOutputStream;
41import java.io.IOException;
42import java.io.InputStreamReader;
43import java.io.PrintStream;
Narayan Kamathc41638c2014-04-07 13:56:15 +010044import java.nio.charset.StandardCharsets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import java.util.ArrayList;
Robert Sesekded20982016-08-15 13:59:13 -040046import java.util.Arrays;
Jeff Brownebed7d62011-05-16 17:08:42 -070047import libcore.io.IoUtils;
Jeff Brownebed7d62011-05-16 17:08:42 -070048
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049/**
50 * A connection that can make spawn requests.
51 */
52class ZygoteConnection {
53 private static final String TAG = "Zygote";
54
55 /** a prototype instance for a future List.toArray() */
56 private static final int[][] intArray2d = new int[0][0];
57
58 /**
59 * {@link android.net.LocalSocket#setSoTimeout} value for connections.
60 * Effectively, the amount of time a requestor has between the start of
61 * the request and the completed request. The select-loop mode Zygote
62 * doesn't have the logic to return to the select loop in the middle of
63 * a request, so we need to time out here to avoid being denial-of-serviced.
64 */
65 private static final int CONNECTION_TIMEOUT_MILLIS = 1000;
66
67 /** max number of arguments that a connection can specify */
Narayan Kamathc41638c2014-04-07 13:56:15 +010068 private static final int MAX_ZYGOTE_ARGC = 1024;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069
70 /**
71 * The command socket.
72 *
73 * mSocket is retained in the child process in "peer wait" mode, so
74 * that it closes when the child process terminates. In other cases,
75 * it is closed in the peer.
76 */
77 private final LocalSocket mSocket;
78 private final DataOutputStream mSocketOutStream;
79 private final BufferedReader mSocketReader;
80 private final Credentials peer;
Narayan Kamathc41638c2014-04-07 13:56:15 +010081 private final String abiList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082
83 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 * Constructs instance from connected socket.
85 *
86 * @param socket non-null; connected socket
Narayan Kamathc41638c2014-04-07 13:56:15 +010087 * @param abiList non-null; a list of ABIs this zygote supports.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 * @throws IOException
89 */
Narayan Kamathc41638c2014-04-07 13:56:15 +010090 ZygoteConnection(LocalSocket socket, String abiList) throws IOException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 mSocket = socket;
Narayan Kamathc41638c2014-04-07 13:56:15 +010092 this.abiList = abiList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093
94 mSocketOutStream
95 = new DataOutputStream(socket.getOutputStream());
96
97 mSocketReader = new BufferedReader(
98 new InputStreamReader(socket.getInputStream()), 256);
99
100 mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
dcashmanfc4c0bf82015-03-05 17:17:47 -0800101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 try {
103 peer = mSocket.getPeerCredentials();
104 } catch (IOException ex) {
105 Log.e(TAG, "Cannot read peer credentials", ex);
106 throw ex;
107 }
108 }
109
110 /**
111 * Returns the file descriptor of the associated socket.
112 *
113 * @return null-ok; file descriptor
114 */
115 FileDescriptor getFileDesciptor() {
116 return mSocket.getFileDescriptor();
117 }
118
119 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 * Reads one start command from the command socket. If successful,
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000121 * a child is forked and a {@link Zygote.MethodAndArgsCaller}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 * exception is thrown in that child while in the parent process,
123 * the method returns normally. On failure, the child is not
124 * spawned and messages are printed to the log and stderr. Returns
125 * a boolean status value indicating whether an end-of-file on the command
126 * socket has been encountered.
127 *
128 * @return false if command socket should continue to be read from, or
129 * true if an end-of-file has been encountered.
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000130 * @throws Zygote.MethodAndArgsCaller trampoline to invoke main()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 * method in child process
132 */
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000133 boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134
135 String args[];
136 Arguments parsedArgs = null;
137 FileDescriptor[] descriptors;
138
139 try {
140 args = readArgumentList();
141 descriptors = mSocket.getAncillaryFileDescriptors();
142 } catch (IOException ex) {
143 Log.w(TAG, "IOException on command socket " + ex.getMessage());
144 closeSocket();
145 return true;
146 }
147
148 if (args == null) {
149 // EOF reached.
150 closeSocket();
151 return true;
152 }
153
154 /** the stderr of the most recent request, if avail */
155 PrintStream newStderr = null;
156
157 if (descriptors != null && descriptors.length >= 3) {
158 newStderr = new PrintStream(
159 new FileOutputStream(descriptors[2]));
160 }
161
Jeff Brownebed7d62011-05-16 17:08:42 -0700162 int pid = -1;
163 FileDescriptor childPipeFd = null;
164 FileDescriptor serverPipeFd = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165
166 try {
167 parsedArgs = new Arguments(args);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100168
169 if (parsedArgs.abiListQuery) {
170 return handleAbiListQuery();
171 }
172
Robert Sesekded20982016-08-15 13:59:13 -0400173 if (parsedArgs.preloadPackage != null) {
174 return handlePreloadPackage(parsedArgs.preloadPackage,
175 parsedArgs.preloadPackageLibs);
176 }
177
Elliott Hughes42a4bb52013-11-07 17:21:03 -0800178 if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
179 throw new ZygoteSecurityException("Client may not specify capabilities: " +
180 "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
181 ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
182 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183
dcashmanfc4c0bf82015-03-05 17:17:47 -0800184 applyUidSecurityPolicy(parsedArgs, peer);
185 applyInvokeWithSecurityPolicy(parsedArgs, peer);
Jeff Brownebed7d62011-05-16 17:08:42 -0700186
187 applyDebuggerSystemProperty(parsedArgs);
188 applyInvokeWithSystemProperty(parsedArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189
190 int[][] rlimits = null;
191
192 if (parsedArgs.rlimits != null) {
193 rlimits = parsedArgs.rlimits.toArray(intArray2d);
194 }
195
Andreas Gampe8dfa1782017-01-05 12:45:58 -0800196 int[] fdsToIgnore = null;
197
Narayan Kamathf48029f2015-01-08 12:45:37 +0000198 if (parsedArgs.invokeWith != null) {
Elliott Hughes3fe59512014-12-12 14:07:34 -0800199 FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
Jeff Brownebed7d62011-05-16 17:08:42 -0700200 childPipeFd = pipeFds[1];
201 serverPipeFd = pipeFds[0];
Narayan Kamath6ac7e672015-01-16 16:26:54 +0000202 Os.fcntlInt(childPipeFd, F_SETFD, 0);
Andreas Gampe8dfa1782017-01-05 12:45:58 -0800203 fdsToIgnore = new int[] { childPipeFd.getInt$(), serverPipeFd.getInt$() };
Jeff Brownebed7d62011-05-16 17:08:42 -0700204 }
205
Dave Platt89d4c892014-02-05 17:06:42 -0800206 /**
207 * In order to avoid leaking descriptors to the Zygote child,
208 * the native code must close the two Zygote socket descriptors
209 * in the child process before it switches from Zygote-root to
210 * the UID and privileges of the application being launched.
211 *
212 * In order to avoid "bad file descriptor" errors when the
213 * two LocalSocket objects are closed, the Posix file
214 * descriptors are released via a dup2() call which closes
215 * the socket and substitutes an open descriptor to /dev/null.
216 */
217
218 int [] fdsToClose = { -1, -1 };
219
220 FileDescriptor fd = mSocket.getFileDescriptor();
221
222 if (fd != null) {
223 fdsToClose[0] = fd.getInt$();
224 }
225
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000226 fd = zygoteServer.getServerSocketFileDescriptor();
Dave Platt89d4c892014-02-05 17:06:42 -0800227
228 if (fd != null) {
229 fdsToClose[1] = fd.getInt$();
230 }
231
232 fd = null;
233
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700234 pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
235 parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
Andreas Gampe8dfa1782017-01-05 12:45:58 -0800236 parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
jgu212eacd062014-09-10 06:55:07 -0400237 parsedArgs.appDataDir);
Jeff Brownebed7d62011-05-16 17:08:42 -0700238 } catch (ErrnoException ex) {
239 logAndPrintError(newStderr, "Exception creating pipe", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 } catch (IllegalArgumentException ex) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700241 logAndPrintError(newStderr, "Invalid zygote arguments", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 } catch (ZygoteSecurityException ex) {
243 logAndPrintError(newStderr,
244 "Zygote security policy prevents request: ", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 }
246
Jeff Brownebed7d62011-05-16 17:08:42 -0700247 try {
248 if (pid == 0) {
249 // in child
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000250 zygoteServer.closeServerSocket();
Jeff Brownebed7d62011-05-16 17:08:42 -0700251 IoUtils.closeQuietly(serverPipeFd);
252 serverPipeFd = null;
253 handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
254
255 // should never get here, the child is expected to either
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000256 // throw Zygote.MethodAndArgsCaller or exec().
Jeff Brownebed7d62011-05-16 17:08:42 -0700257 return true;
258 } else {
259 // in parent...pid of < 0 means failure
260 IoUtils.closeQuietly(childPipeFd);
261 childPipeFd = null;
262 return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
263 }
264 } finally {
265 IoUtils.closeQuietly(childPipeFd);
266 IoUtils.closeQuietly(serverPipeFd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 }
268 }
269
Narayan Kamathc41638c2014-04-07 13:56:15 +0100270 private boolean handleAbiListQuery() {
271 try {
272 final byte[] abiListBytes = abiList.getBytes(StandardCharsets.US_ASCII);
273 mSocketOutStream.writeInt(abiListBytes.length);
274 mSocketOutStream.write(abiListBytes);
275 return false;
276 } catch (IOException ioe) {
277 Log.e(TAG, "Error writing to command socket", ioe);
278 return true;
279 }
280 }
281
Robert Sesekded20982016-08-15 13:59:13 -0400282 protected boolean handlePreloadPackage(String packagePath, String libsPath) {
283 throw new RuntimeException("Zyogte does not support package preloading");
284 }
285
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 /**
287 * Closes socket associated with this connection.
288 */
289 void closeSocket() {
290 try {
291 mSocket.close();
292 } catch (IOException ex) {
293 Log.e(TAG, "Exception while closing command "
294 + "socket in parent", ex);
295 }
296 }
297
298 /**
Jeff Brownebed7d62011-05-16 17:08:42 -0700299 * Handles argument parsing for args related to the zygote spawner.
300 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 * Current recognized args:
302 * <ul>
303 * <li> --setuid=<i>uid of child process, defaults to 0</i>
304 * <li> --setgid=<i>gid of child process, defaults to 0</i>
305 * <li> --setgroups=<i>comma-separated list of supplimentary gid's</i>
306 * <li> --capabilities=<i>a pair of comma-separated integer strings
307 * indicating Linux capabilities(2) set for child. The first string
308 * represents the <code>permitted</code> set, and the second the
309 * <code>effective</code> set. Precede each with 0 or
310 * 0x for octal or hexidecimal value. If unspecified, both default to 0.
311 * This parameter is only applied if the uid of the new process will
312 * be non-0. </i>
313 * <li> --rlimit=r,c,m<i>tuple of values for setrlimit() call.
314 * <code>r</code> is the resource, <code>c</code> and <code>m</code>
315 * are the settings for current and max value.</i>
Andreas Gampeaec67dc2014-09-02 21:23:06 -0700316 * <li> --instruction-set=<i>instruction-set-string</i> which instruction set to use/emulate.
Narayan Kamathf48029f2015-01-08 12:45:37 +0000317 * <li> --nice-name=<i>nice name to appear in ps</i>
318 * <li> --runtime-args indicates that the remaining arg list should
319 * be handed off to com.android.internal.os.RuntimeInit, rather than
320 * processed directly.
321 * Android runtime startup (eg, Binder initialization) is also eschewed.
322 * <li> [--] &lt;args for RuntimeInit &gt;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323 * </ul>
324 */
325 static class Arguments {
326 /** from --setuid */
327 int uid = 0;
328 boolean uidSpecified;
329
330 /** from --setgid */
331 int gid = 0;
332 boolean gidSpecified;
333
334 /** from --setgroups */
335 int[] gids;
336
Ben Cheng23085b72010-02-08 16:06:32 -0800337 /**
Elliott Hughesae07ecf2011-07-06 17:33:27 -0700338 * From --enable-debugger, --enable-checkjni, --enable-assert,
Nicolas Geoffray9abbf452015-11-05 11:29:42 +0000339 * --enable-safemode, --generate-debug-info and --enable-jni-logging.
Ben Cheng23085b72010-02-08 16:06:32 -0800340 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 int debugFlags;
342
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700343 /** From --mount-external */
344 int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
345
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700346 /** from --target-sdk-version. */
347 int targetSdkVersion;
348 boolean targetSdkVersionSpecified;
349
Jeff Brownebed7d62011-05-16 17:08:42 -0700350 /** from --nice-name */
351 String niceName;
352
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 /** from --capabilities */
354 boolean capabilitiesSpecified;
355 long permittedCapabilities;
356 long effectiveCapabilities;
357
Stephen Smalley83d9eda2012-01-13 08:34:17 -0500358 /** from --seinfo */
359 boolean seInfoSpecified;
360 String seInfo;
361
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 /** from all --rlimit=r,c,m */
363 ArrayList<int[]> rlimits;
364
Jeff Brownebed7d62011-05-16 17:08:42 -0700365 /** from --invoke-with */
366 String invokeWith;
367
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 /**
369 * Any args after and including the first non-option arg
370 * (or after a '--')
371 */
372 String remainingArgs[];
373
374 /**
Narayan Kamathc41638c2014-04-07 13:56:15 +0100375 * Whether the current arguments constitute an ABI list query.
376 */
377 boolean abiListQuery;
378
379 /**
Andreas Gampeaec67dc2014-09-02 21:23:06 -0700380 * The instruction set to use, or null when not important.
381 */
382 String instructionSet;
383
384 /**
jgu212eacd062014-09-10 06:55:07 -0400385 * The app data directory. May be null, e.g., for the system server. Note that this might
386 * not be reliable in the case of process-sharing apps.
387 */
388 String appDataDir;
389
390 /**
Robert Sesekded20982016-08-15 13:59:13 -0400391 * Whether to preload a package, with the package path in the remainingArgs.
392 */
393 String preloadPackage;
394 String preloadPackageLibs;
395
396 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 * Constructs instance and parses args
398 * @param args zygote command-line args
399 * @throws IllegalArgumentException
400 */
401 Arguments(String args[]) throws IllegalArgumentException {
402 parseArgs(args);
403 }
404
405 /**
406 * Parses the commandline arguments intended for the Zygote spawner
407 * (such as "--setuid=" and "--setgid=") and creates an array
408 * containing the remaining args.
409 *
410 * Per security review bug #1112214, duplicate args are disallowed in
411 * critical cases to make injection harder.
412 */
413 private void parseArgs(String args[])
414 throws IllegalArgumentException {
415 int curArg = 0;
416
Narayan Kamathb6b044a2015-02-13 17:31:25 +0000417 boolean seenRuntimeArgs = false;
Narayan Kamathf48029f2015-01-08 12:45:37 +0000418
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 for ( /* curArg */ ; curArg < args.length; curArg++) {
420 String arg = args[curArg];
421
422 if (arg.equals("--")) {
423 curArg++;
424 break;
425 } else if (arg.startsWith("--setuid=")) {
426 if (uidSpecified) {
427 throw new IllegalArgumentException(
428 "Duplicate arg specified");
429 }
430 uidSpecified = true;
431 uid = Integer.parseInt(
432 arg.substring(arg.indexOf('=') + 1));
433 } else if (arg.startsWith("--setgid=")) {
434 if (gidSpecified) {
435 throw new IllegalArgumentException(
436 "Duplicate arg specified");
437 }
438 gidSpecified = true;
439 gid = Integer.parseInt(
440 arg.substring(arg.indexOf('=') + 1));
Elliott Hughese1dfcb72011-07-08 11:08:07 -0700441 } else if (arg.startsWith("--target-sdk-version=")) {
442 if (targetSdkVersionSpecified) {
443 throw new IllegalArgumentException(
444 "Duplicate target-sdk-version specified");
445 }
446 targetSdkVersionSpecified = true;
447 targetSdkVersion = Integer.parseInt(
448 arg.substring(arg.indexOf('=') + 1));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 } else if (arg.equals("--enable-debugger")) {
450 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
Ben Cheng23085b72010-02-08 16:06:32 -0800451 } else if (arg.equals("--enable-safemode")) {
452 debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 } else if (arg.equals("--enable-checkjni")) {
454 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
David Srbecky065075e2015-05-28 17:16:09 +0100455 } else if (arg.equals("--generate-debug-info")) {
456 debugFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO;
Tamas Berghammerdf6cb282016-01-29 12:07:00 +0000457 } else if (arg.equals("--always-jit")) {
458 debugFlags |= Zygote.DEBUG_ALWAYS_JIT;
459 } else if (arg.equals("--native-debuggable")) {
460 debugFlags |= Zygote.DEBUG_NATIVE_DEBUGGABLE;
Elliott Hughesae07ecf2011-07-06 17:33:27 -0700461 } else if (arg.equals("--enable-jni-logging")) {
462 debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 } else if (arg.equals("--enable-assert")) {
464 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
Narayan Kamathf48029f2015-01-08 12:45:37 +0000465 } else if (arg.equals("--runtime-args")) {
466 seenRuntimeArgs = true;
Stephen Smalley83d9eda2012-01-13 08:34:17 -0500467 } else if (arg.startsWith("--seinfo=")) {
468 if (seInfoSpecified) {
469 throw new IllegalArgumentException(
470 "Duplicate arg specified");
471 }
472 seInfoSpecified = true;
473 seInfo = arg.substring(arg.indexOf('=') + 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 } else if (arg.startsWith("--capabilities=")) {
475 if (capabilitiesSpecified) {
476 throw new IllegalArgumentException(
477 "Duplicate arg specified");
478 }
479 capabilitiesSpecified = true;
480 String capString = arg.substring(arg.indexOf('=')+1);
481
482 String[] capStrings = capString.split(",", 2);
483
484 if (capStrings.length == 1) {
485 effectiveCapabilities = Long.decode(capStrings[0]);
486 permittedCapabilities = effectiveCapabilities;
487 } else {
488 permittedCapabilities = Long.decode(capStrings[0]);
489 effectiveCapabilities = Long.decode(capStrings[1]);
490 }
491 } else if (arg.startsWith("--rlimit=")) {
492 // Duplicate --rlimit arguments are specifically allowed.
493 String[] limitStrings
494 = arg.substring(arg.indexOf('=')+1).split(",");
495
496 if (limitStrings.length != 3) {
497 throw new IllegalArgumentException(
498 "--rlimit= should have 3 comma-delimited ints");
499 }
500 int[] rlimitTuple = new int[limitStrings.length];
501
502 for(int i=0; i < limitStrings.length; i++) {
503 rlimitTuple[i] = Integer.parseInt(limitStrings[i]);
504 }
505
506 if (rlimits == null) {
507 rlimits = new ArrayList();
508 }
509
510 rlimits.add(rlimitTuple);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 } else if (arg.startsWith("--setgroups=")) {
512 if (gids != null) {
513 throw new IllegalArgumentException(
514 "Duplicate arg specified");
515 }
516
517 String[] params
518 = arg.substring(arg.indexOf('=') + 1).split(",");
519
520 gids = new int[params.length];
521
522 for (int i = params.length - 1; i >= 0 ; i--) {
523 gids[i] = Integer.parseInt(params[i]);
524 }
Jeff Brownebed7d62011-05-16 17:08:42 -0700525 } else if (arg.equals("--invoke-with")) {
526 if (invokeWith != null) {
527 throw new IllegalArgumentException(
528 "Duplicate arg specified");
529 }
530 try {
531 invokeWith = args[++curArg];
532 } catch (IndexOutOfBoundsException ex) {
533 throw new IllegalArgumentException(
534 "--invoke-with requires argument");
535 }
536 } else if (arg.startsWith("--nice-name=")) {
537 if (niceName != null) {
538 throw new IllegalArgumentException(
539 "Duplicate arg specified");
540 }
541 niceName = arg.substring(arg.indexOf('=') + 1);
Jeff Sharkey48877892015-03-18 11:27:19 -0700542 } else if (arg.equals("--mount-external-default")) {
543 mountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT;
Jeff Sharkey9527b222015-06-24 15:24:48 -0700544 } else if (arg.equals("--mount-external-read")) {
545 mountExternal = Zygote.MOUNT_EXTERNAL_READ;
546 } else if (arg.equals("--mount-external-write")) {
547 mountExternal = Zygote.MOUNT_EXTERNAL_WRITE;
Narayan Kamathc41638c2014-04-07 13:56:15 +0100548 } else if (arg.equals("--query-abi-list")) {
549 abiListQuery = true;
Andreas Gampeaec67dc2014-09-02 21:23:06 -0700550 } else if (arg.startsWith("--instruction-set=")) {
551 instructionSet = arg.substring(arg.indexOf('=') + 1);
jgu212eacd062014-09-10 06:55:07 -0400552 } else if (arg.startsWith("--app-data-dir=")) {
553 appDataDir = arg.substring(arg.indexOf('=') + 1);
Robert Sesekded20982016-08-15 13:59:13 -0400554 } else if (arg.equals("--preload-package")) {
555 preloadPackage = args[++curArg];
556 preloadPackageLibs = args[++curArg];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 } else {
558 break;
559 }
560 }
561
Narayan Kamathb6b044a2015-02-13 17:31:25 +0000562 if (abiListQuery) {
563 if (args.length - curArg > 0) {
564 throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
565 }
Robert Sesekded20982016-08-15 13:59:13 -0400566 } else if (preloadPackage != null) {
567 if (args.length - curArg > 0) {
568 throw new IllegalArgumentException(
569 "Unexpected arguments after --preload-package.");
570 }
Narayan Kamathb6b044a2015-02-13 17:31:25 +0000571 } else {
572 if (!seenRuntimeArgs) {
573 throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
574 }
575
576 remainingArgs = new String[args.length - curArg];
577 System.arraycopy(args, curArg, remainingArgs, 0, remainingArgs.length);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 }
580 }
581
582 /**
583 * Reads an argument list from the command socket/
584 * @return Argument list or null if EOF is reached
585 * @throws IOException passed straight through
586 */
587 private String[] readArgumentList()
588 throws IOException {
589
590 /**
591 * See android.os.Process.zygoteSendArgsAndGetPid()
592 * Presently the wire format to the zygote process is:
593 * a) a count of arguments (argc, in essence)
594 * b) a number of newline-separated argument strings equal to count
595 *
596 * After the zygote process reads these it will write the pid of
597 * the child or -1 on failure.
598 */
599
600 int argc;
601
602 try {
603 String s = mSocketReader.readLine();
604
605 if (s == null) {
606 // EOF reached.
607 return null;
608 }
609 argc = Integer.parseInt(s);
610 } catch (NumberFormatException ex) {
611 Log.e(TAG, "invalid Zygote wire format: non-int at argc");
612 throw new IOException("invalid wire format");
613 }
614
615 // See bug 1092107: large argc can be used for a DOS attack
dcashmanfc4c0bf82015-03-05 17:17:47 -0800616 if (argc > MAX_ZYGOTE_ARGC) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800617 throw new IOException("max arg count exceeded");
618 }
619
620 String[] result = new String[argc];
621 for (int i = 0; i < argc; i++) {
622 result[i] = mSocketReader.readLine();
623 if (result[i] == null) {
624 // We got an unexpected EOF.
625 throw new IOException("truncated request");
626 }
627 }
628
629 return result;
630 }
631
632 /**
dcashmanfc4c0bf82015-03-05 17:17:47 -0800633 * uid 1000 (Process.SYSTEM_UID) may specify any uid &gt; 1000 in normal
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634 * operation. It may also specify any gid and setgroups() list it chooses.
635 * In factory test mode, it may specify any UID.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 *
637 * @param args non-null; zygote spawner arguments
638 * @param peer non-null; peer credentials
639 * @throws ZygoteSecurityException
640 */
dcashmanfc4c0bf82015-03-05 17:17:47 -0800641 private static void applyUidSecurityPolicy(Arguments args, Credentials peer)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 throws ZygoteSecurityException {
643
dcashmanfc4c0bf82015-03-05 17:17:47 -0800644 if (peer.getUid() == Process.SYSTEM_UID) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 String factoryTest = SystemProperties.get("ro.factorytest");
646 boolean uidRestricted;
647
648 /* In normal operation, SYSTEM_UID can only specify a restricted
649 * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
650 */
dcashmanfc4c0bf82015-03-05 17:17:47 -0800651 uidRestricted = !(factoryTest.equals("1") || factoryTest.equals("2"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652
dcashmanfc4c0bf82015-03-05 17:17:47 -0800653 if (uidRestricted && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 throw new ZygoteSecurityException(
655 "System UID may not launch process with UID < "
dcashmanfc4c0bf82015-03-05 17:17:47 -0800656 + Process.SYSTEM_UID);
Stephen Smalley83d9eda2012-01-13 08:34:17 -0500657 }
658 }
659
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 // If not otherwise specified, uid and gid are inherited from peer
661 if (!args.uidSpecified) {
662 args.uid = peer.getUid();
663 args.uidSpecified = true;
664 }
665 if (!args.gidSpecified) {
666 args.gid = peer.getGid();
667 args.gidSpecified = true;
668 }
669 }
670
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 /**
Jeff Brownebed7d62011-05-16 17:08:42 -0700672 * Applies debugger system properties to the zygote arguments.
673 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 * If "ro.debuggable" is "1", all apps are debuggable. Otherwise,
675 * the debugger state is specified via the "--enable-debugger" flag
676 * in the spawn request.
677 *
678 * @param args non-null; zygote spawner args
679 */
Jeff Brownebed7d62011-05-16 17:08:42 -0700680 public static void applyDebuggerSystemProperty(Arguments args) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 if ("1".equals(SystemProperties.get("ro.debuggable"))) {
682 args.debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
683 }
684 }
685
686 /**
Jeff Brownebed7d62011-05-16 17:08:42 -0700687 * Applies zygote security policy.
688 * Based on the credentials of the process issuing a zygote command:
689 * <ol>
690 * <li> uid 0 (root) may specify --invoke-with to launch Zygote with a
691 * wrapper command.
692 * <li> Any other uid may not specify any invoke-with argument.
693 * </ul>
694 *
695 * @param args non-null; zygote spawner arguments
696 * @param peer non-null; peer credentials
697 * @throws ZygoteSecurityException
698 */
dcashmanfc4c0bf82015-03-05 17:17:47 -0800699 private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer)
Jeff Brownebed7d62011-05-16 17:08:42 -0700700 throws ZygoteSecurityException {
701 int peerUid = peer.getUid();
702
Tamas Berghammer0ca16fa2016-11-11 16:08:26 +0000703 if (args.invokeWith != null && peerUid != 0 &&
704 (args.debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) == 0) {
705 throw new ZygoteSecurityException("Peer is permitted to specify an"
706 + "explicit invoke-with wrapper command only for debuggable"
707 + "applications.");
Jeff Brownebed7d62011-05-16 17:08:42 -0700708 }
709 }
710
711 /**
712 * Applies invoke-with system properties to the zygote arguments.
713 *
Narayan Kamath973b4662014-03-31 13:41:26 +0100714 * @param args non-null; zygote args
Jeff Brownebed7d62011-05-16 17:08:42 -0700715 */
716 public static void applyInvokeWithSystemProperty(Arguments args) {
717 if (args.invokeWith == null && args.niceName != null) {
dcashmanfc4c0bf82015-03-05 17:17:47 -0800718 String property = "wrap." + args.niceName;
719 if (property.length() > 31) {
720 // Properties with a trailing "." are illegal.
721 if (property.charAt(30) != '.') {
722 property = property.substring(0, 31);
723 } else {
724 property = property.substring(0, 30);
Jeff Brownebed7d62011-05-16 17:08:42 -0700725 }
dcashmanfc4c0bf82015-03-05 17:17:47 -0800726 }
727 args.invokeWith = SystemProperties.get(property);
728 if (args.invokeWith != null && args.invokeWith.length() == 0) {
729 args.invokeWith = null;
Jeff Brownebed7d62011-05-16 17:08:42 -0700730 }
731 }
732 }
733
734 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735 * Handles post-fork setup of child proc, closing sockets as appropriate,
736 * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
737 * if successful or returning if failed.
738 *
739 * @param parsedArgs non-null; zygote args
740 * @param descriptors null-ok; new file descriptors for stdio if available.
Jeff Brownebed7d62011-05-16 17:08:42 -0700741 * @param pipeFd null-ok; pipe for communication back to Zygote.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 * @param newStderr null-ok; stream to use for stderr until stdio
743 * is reopened.
744 *
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000745 * @throws Zygote.MethodAndArgsCaller on success to
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800746 * trampoline to code that invokes static main.
747 */
748 private void handleChildProc(Arguments parsedArgs,
Jeff Brownebed7d62011-05-16 17:08:42 -0700749 FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000750 throws Zygote.MethodAndArgsCaller {
Dave Platt89d4c892014-02-05 17:06:42 -0800751 /**
752 * By the time we get here, the native code has closed the two actual Zygote
753 * socket connections, and substituted /dev/null in their place. The LocalSocket
754 * objects still need to be closed properly.
755 */
756
Nick Kralevich468f6c12013-01-30 08:45:03 -0800757 closeSocket();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 if (descriptors != null) {
759 try {
Elliott Hughesdac83f52014-12-15 11:00:25 -0800760 Os.dup2(descriptors[0], STDIN_FILENO);
761 Os.dup2(descriptors[1], STDOUT_FILENO);
762 Os.dup2(descriptors[2], STDERR_FILENO);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763
764 for (FileDescriptor fd: descriptors) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700765 IoUtils.closeQuietly(fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 }
767 newStderr = System.err;
Elliott Hughesdac83f52014-12-15 11:00:25 -0800768 } catch (ErrnoException ex) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 Log.e(TAG, "Error reopening stdio", ex);
770 }
771 }
772
Jeff Brownebed7d62011-05-16 17:08:42 -0700773 if (parsedArgs.niceName != null) {
774 Process.setArgV0(parsedArgs.niceName);
775 }
776
Narayan Kamathfbb32f62015-06-12 15:34:35 +0100777 // End of the postFork event.
778 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Narayan Kamathf48029f2015-01-08 12:45:37 +0000779 if (parsedArgs.invokeWith != null) {
780 WrapperInit.execApplication(parsedArgs.invokeWith,
781 parsedArgs.niceName, parsedArgs.targetSdkVersion,
Narayan Kamath37ad4b02015-01-19 16:05:24 +0000782 VMRuntime.getCurrentInstructionSet(),
Narayan Kamathf48029f2015-01-08 12:45:37 +0000783 pipeFd, parsedArgs.remainingArgs);
Jeff Brownebed7d62011-05-16 17:08:42 -0700784 } else {
Narayan Kamathf48029f2015-01-08 12:45:37 +0000785 RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
786 parsedArgs.remainingArgs, null /* classLoader */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 }
788 }
789
790 /**
791 * Handles post-fork cleanup of parent proc
792 *
793 * @param pid != 0; pid of child if &gt; 0 or indication of failed fork
794 * if &lt; 0;
795 * @param descriptors null-ok; file descriptors for child's new stdio if
796 * specified.
Jeff Brownebed7d62011-05-16 17:08:42 -0700797 * @param pipeFd null-ok; pipe for communication with child.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 * @param parsedArgs non-null; zygote args
799 * @return true for "exit command loop" and false for "continue command
800 * loop"
801 */
802 private boolean handleParentProc(int pid,
Jeff Brownebed7d62011-05-16 17:08:42 -0700803 FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804
Jeff Brownebed7d62011-05-16 17:08:42 -0700805 if (pid > 0) {
806 setChildPgid(pid);
807 }
808
809 if (descriptors != null) {
810 for (FileDescriptor fd: descriptors) {
811 IoUtils.closeQuietly(fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 }
813 }
814
Jeff Brown3f9dd282011-07-08 20:02:19 -0700815 boolean usingWrapper = false;
Jeff Brownebed7d62011-05-16 17:08:42 -0700816 if (pipeFd != null && pid > 0) {
817 DataInputStream is = new DataInputStream(new FileInputStream(pipeFd));
818 int innerPid = -1;
819 try {
820 innerPid = is.readInt();
821 } catch (IOException ex) {
822 Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
823 } finally {
824 try {
825 is.close();
826 } catch (IOException ex) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 }
828 }
Jeff Brownebed7d62011-05-16 17:08:42 -0700829
830 // Ensure that the pid reported by the wrapped process is either the
831 // child process that we forked, or a descendant of it.
832 if (innerPid > 0) {
833 int parentPid = innerPid;
834 while (parentPid > 0 && parentPid != pid) {
835 parentPid = Process.getParentPid(parentPid);
836 }
837 if (parentPid > 0) {
838 Log.i(TAG, "Wrapped process has pid " + innerPid);
839 pid = innerPid;
Jeff Brown3f9dd282011-07-08 20:02:19 -0700840 usingWrapper = true;
Jeff Brownebed7d62011-05-16 17:08:42 -0700841 } else {
842 Log.w(TAG, "Wrapped process reported a pid that is not a child of "
843 + "the process that we forked: childPid=" + pid
844 + " innerPid=" + innerPid);
845 }
846 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 }
848
849 try {
850 mSocketOutStream.writeInt(pid);
Jeff Brown3f9dd282011-07-08 20:02:19 -0700851 mSocketOutStream.writeBoolean(usingWrapper);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 } catch (IOException ex) {
Narayan Kamathc41638c2014-04-07 13:56:15 +0100853 Log.e(TAG, "Error writing to command socket", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 return true;
855 }
856
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 return false;
858 }
859
Jeff Brownebed7d62011-05-16 17:08:42 -0700860 private void setChildPgid(int pid) {
861 // Try to move the new child into the peer's process group.
862 try {
Elliott Hughes26b56e62014-12-17 12:28:29 -0800863 Os.setpgid(pid, Os.getpgid(peer.getPid()));
864 } catch (ErrnoException ex) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700865 // This exception is expected in the case where
866 // the peer is not in our session
867 // TODO get rid of this log message in the case where
868 // getsid(0) != getsid(peer.getPid())
869 Log.i(TAG, "Zygote: setpgid failed. This is "
870 + "normal if peer is not in our session");
871 }
872 }
873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 /**
875 * Logs an error message and prints it to the specified stream, if
876 * provided
877 *
878 * @param newStderr null-ok; a standard error stream
879 * @param message non-null; error message
880 * @param ex null-ok an exception
881 */
882 private static void logAndPrintError (PrintStream newStderr,
883 String message, Throwable ex) {
884 Log.e(TAG, message, ex);
885 if (newStderr != null) {
886 newStderr.println(message + (ex == null ? "" : ex));
887 }
888 }
889}