blob: 28642d8ba80cf8e43eb9f05f95a9deace8caba5d [file] [log] [blame]
Chris Wailes2be26262019-01-11 16:14:43 -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
19import java.util.ArrayList;
20import java.util.Arrays;
21
22/**
23 * Handles argument parsing for args related to the zygote spawner.
24 *
25 * Current recognized args:
26 * <ul>
27 * <li> --setuid=<i>uid of child process, defaults to 0</i>
28 * <li> --setgid=<i>gid of child process, defaults to 0</i>
29 * <li> --setgroups=<i>comma-separated list of supplimentary gid's</i>
30 * <li> --capabilities=<i>a pair of comma-separated integer strings
31 * indicating Linux capabilities(2) set for child. The first string
32 * represents the <code>permitted</code> set, and the second the
33 * <code>effective</code> set. Precede each with 0 or
34 * 0x for octal or hexidecimal value. If unspecified, both default to 0.
35 * This parameter is only applied if the uid of the new process will
36 * be non-0. </i>
37 * <li> --rlimit=r,c,m<i>tuple of values for setrlimit() call.
38 * <code>r</code> is the resource, <code>c</code> and <code>m</code>
39 * are the settings for current and max value.</i>
40 * <li> --instruction-set=<i>instruction-set-string</i> which instruction set to use/emulate.
41 * <li> --nice-name=<i>nice name to appear in ps</i>
42 * <li> --package-name=<i>package name this process belongs to</i>
43 * <li> --runtime-args indicates that the remaining arg list should
44 * be handed off to com.android.internal.os.RuntimeInit, rather than
45 * processed directly.
46 * Android runtime startup (eg, Binder initialization) is also eschewed.
47 * <li> [--] &lt;args for RuntimeInit &gt;
48 * </ul>
49 */
50class ZygoteArguments {
51
52 /**
53 * from --setuid
54 */
55 int mUid = 0;
56 boolean mUidSpecified;
57
58 /**
59 * from --setgid
60 */
61 int mGid = 0;
62 boolean mGidSpecified;
63
64 /**
65 * from --setgroups
66 */
67 int[] mGids;
68
69 /**
70 * From --runtime-flags.
71 */
72 int mRuntimeFlags;
73
74 /**
75 * From --mount-external
76 */
77 int mMountExternal = Zygote.MOUNT_EXTERNAL_NONE;
78
79 /**
80 * from --target-sdk-version.
81 */
82 int mTargetSdkVersion;
83 boolean mTargetSdkVersionSpecified;
84
85 /**
86 * from --nice-name
87 */
88 String mNiceName;
89
90 /**
91 * from --capabilities
92 */
93 boolean mCapabilitiesSpecified;
94 long mPermittedCapabilities;
95 long mEffectiveCapabilities;
96
97 /**
98 * from --seinfo
99 */
100 boolean mSeInfoSpecified;
101 String mSeInfo;
102
103 /**
Chris Wailesdb132a32019-02-20 10:49:27 -0800104 *
105 */
Chris Wailes7e797b62019-02-22 18:29:22 -0800106 boolean mUsapPoolEnabled;
107 boolean mUsapPoolStatusSpecified = false;
Chris Wailesdb132a32019-02-20 10:49:27 -0800108
109 /**
Chris Wailes2be26262019-01-11 16:14:43 -0800110 * from all --rlimit=r,c,m
111 */
112 ArrayList<int[]> mRLimits;
113
114 /**
115 * from --invoke-with
116 */
117 String mInvokeWith;
118
119 /** from --package-name */
120 String mPackageName;
121
122 /** from --packages-for-uid */
123 String[] mPackagesForUid;
124
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800125 /** from --sandbox-id */
126 String mSandboxId;
127
Chris Wailes2be26262019-01-11 16:14:43 -0800128 /**
129 * Any args after and including the first non-option arg (or after a '--')
130 */
131 String[] mRemainingArgs;
132
133 /**
134 * Whether the current arguments constitute an ABI list query.
135 */
136 boolean mAbiListQuery;
137
138 /**
139 * The instruction set to use, or null when not important.
140 */
141 String mInstructionSet;
142
143 /**
144 * The app data directory. May be null, e.g., for the system server. Note that this might not be
145 * reliable in the case of process-sharing apps.
146 */
147 String mAppDataDir;
148
149 /**
150 * The APK path of the package to preload, when using --preload-package.
151 */
152 String mPreloadPackage;
153
154 /**
155 * A Base64 string representing a serialize ApplicationInfo Parcel,
156 when using --preload-app.
157 */
158 String mPreloadApp;
159
160 /**
161 * The native library path of the package to preload, when using --preload-package.
162 */
163 String mPreloadPackageLibs;
164
165 /**
166 * The filename of the native library to preload, when using --preload-package.
167 */
168 String mPreloadPackageLibFileName;
169
170 /**
171 * The cache key under which to enter the preloaded package into the classloader cache, when
172 * using --preload-package.
173 */
174 String mPreloadPackageCacheKey;
175
176 /**
177 * Whether this is a request to start preloading the default resources and classes. This
178 * argument only makes sense when the zygote is in lazy preload mode (i.e, when it's started
179 * with --enable-lazy-preload).
180 */
181 boolean mPreloadDefault;
182
183 /**
184 * Whether this is a request to start a zygote process as a child of this zygote. Set with
185 * --start-child-zygote. The remaining arguments must include the CHILD_ZYGOTE_SOCKET_NAME_ARG
186 * flag to indicate the abstract socket name that should be used for communication.
187 */
188 boolean mStartChildZygote;
189
190 /**
191 * Whether the current arguments constitute a request for the zygote's PID.
192 */
193 boolean mPidQuery;
194
195 /**
196 * Exemptions from API blacklisting. These are sent to the pre-forked zygote at boot time, or
197 * when they change, via --set-api-blacklist-exemptions.
198 */
199 String[] mApiBlacklistExemptions;
200
201 /**
202 * Sampling rate for logging hidden API accesses to the event log. This is sent to the
203 * pre-forked zygote at boot time, or when it changes, via --hidden-api-log-sampling-rate.
204 */
205 int mHiddenApiAccessLogSampleRate = -1;
206
207 /**
Andrei Oneae8e150d2019-02-18 18:27:11 +0000208 * Sampling rate for logging hidden API accesses to statslog. This is sent to the
209 * pre-forked zygote at boot time, or when it changes, via --hidden-api-statslog-sampling-rate.
210 */
211 int mHiddenApiAccessStatslogSampleRate = -1;
212
213 /**
Chris Wailes2be26262019-01-11 16:14:43 -0800214 * Constructs instance and parses args
215 *
216 * @param args zygote command-line args
217 */
218 ZygoteArguments(String[] args) throws IllegalArgumentException {
219 parseArgs(args);
220 }
221
222 /**
223 * Parses the commandline arguments intended for the Zygote spawner (such as "--setuid=" and
224 * "--setgid=") and creates an array containing the remaining args.
225 *
226 * Per security review bug #1112214, duplicate args are disallowed in critical cases to make
227 * injection harder.
228 */
Chris Wailesb13bfc52019-02-20 11:19:48 -0800229 private void parseArgs(String[] args) throws IllegalArgumentException {
230 /*
231 * See android.os.ZygoteProcess.zygoteSendArgsAndGetResult()
232 * Presently the wire format to the zygote process is:
233 * a) a count of arguments (argc, in essence)
234 * b) a number of newline-separated argument strings equal to count
235 *
236 * After the zygote process reads these it will write the pid of
237 * the child or -1 on failure.
238 */
239
Chris Wailes2be26262019-01-11 16:14:43 -0800240 int curArg = 0;
241
242 boolean seenRuntimeArgs = false;
243
244 boolean expectRuntimeArgs = true;
245 for ( /* curArg */ ; curArg < args.length; curArg++) {
246 String arg = args[curArg];
247
248 if (arg.equals("--")) {
249 curArg++;
250 break;
251 } else if (arg.startsWith("--setuid=")) {
252 if (mUidSpecified) {
253 throw new IllegalArgumentException(
254 "Duplicate arg specified");
255 }
256 mUidSpecified = true;
257 mUid = Integer.parseInt(
258 arg.substring(arg.indexOf('=') + 1));
259 } else if (arg.startsWith("--setgid=")) {
260 if (mGidSpecified) {
261 throw new IllegalArgumentException(
262 "Duplicate arg specified");
263 }
264 mGidSpecified = true;
265 mGid = Integer.parseInt(
266 arg.substring(arg.indexOf('=') + 1));
267 } else if (arg.startsWith("--target-sdk-version=")) {
268 if (mTargetSdkVersionSpecified) {
269 throw new IllegalArgumentException(
270 "Duplicate target-sdk-version specified");
271 }
272 mTargetSdkVersionSpecified = true;
273 mTargetSdkVersion = Integer.parseInt(
274 arg.substring(arg.indexOf('=') + 1));
275 } else if (arg.equals("--runtime-args")) {
276 seenRuntimeArgs = true;
277 } else if (arg.startsWith("--runtime-flags=")) {
278 mRuntimeFlags = Integer.parseInt(
279 arg.substring(arg.indexOf('=') + 1));
280 } else if (arg.startsWith("--seinfo=")) {
281 if (mSeInfoSpecified) {
282 throw new IllegalArgumentException(
283 "Duplicate arg specified");
284 }
285 mSeInfoSpecified = true;
286 mSeInfo = arg.substring(arg.indexOf('=') + 1);
287 } else if (arg.startsWith("--capabilities=")) {
288 if (mCapabilitiesSpecified) {
289 throw new IllegalArgumentException(
290 "Duplicate arg specified");
291 }
292 mCapabilitiesSpecified = true;
293 String capString = arg.substring(arg.indexOf('=') + 1);
294
295 String[] capStrings = capString.split(",", 2);
296
297 if (capStrings.length == 1) {
298 mEffectiveCapabilities = Long.decode(capStrings[0]);
299 mPermittedCapabilities = mEffectiveCapabilities;
300 } else {
301 mPermittedCapabilities = Long.decode(capStrings[0]);
302 mEffectiveCapabilities = Long.decode(capStrings[1]);
303 }
304 } else if (arg.startsWith("--rlimit=")) {
305 // Duplicate --rlimit arguments are specifically allowed.
306 String[] limitStrings = arg.substring(arg.indexOf('=') + 1).split(",");
307
308 if (limitStrings.length != 3) {
309 throw new IllegalArgumentException(
310 "--rlimit= should have 3 comma-delimited ints");
311 }
312 int[] rlimitTuple = new int[limitStrings.length];
313
314 for (int i = 0; i < limitStrings.length; i++) {
315 rlimitTuple[i] = Integer.parseInt(limitStrings[i]);
316 }
317
318 if (mRLimits == null) {
319 mRLimits = new ArrayList();
320 }
321
322 mRLimits.add(rlimitTuple);
323 } else if (arg.startsWith("--setgroups=")) {
324 if (mGids != null) {
325 throw new IllegalArgumentException(
326 "Duplicate arg specified");
327 }
328
329 String[] params = arg.substring(arg.indexOf('=') + 1).split(",");
330
331 mGids = new int[params.length];
332
333 for (int i = params.length - 1; i >= 0; i--) {
334 mGids[i] = Integer.parseInt(params[i]);
335 }
336 } else if (arg.equals("--invoke-with")) {
337 if (mInvokeWith != null) {
338 throw new IllegalArgumentException(
339 "Duplicate arg specified");
340 }
341 try {
342 mInvokeWith = args[++curArg];
343 } catch (IndexOutOfBoundsException ex) {
344 throw new IllegalArgumentException(
345 "--invoke-with requires argument");
346 }
347 } else if (arg.startsWith("--nice-name=")) {
348 if (mNiceName != null) {
349 throw new IllegalArgumentException(
350 "Duplicate arg specified");
351 }
352 mNiceName = arg.substring(arg.indexOf('=') + 1);
353 } else if (arg.equals("--mount-external-default")) {
354 mMountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT;
355 } else if (arg.equals("--mount-external-read")) {
356 mMountExternal = Zygote.MOUNT_EXTERNAL_READ;
357 } else if (arg.equals("--mount-external-write")) {
358 mMountExternal = Zygote.MOUNT_EXTERNAL_WRITE;
359 } else if (arg.equals("--mount-external-full")) {
360 mMountExternal = Zygote.MOUNT_EXTERNAL_FULL;
361 } else if (arg.equals("--mount-external-installer")) {
362 mMountExternal = Zygote.MOUNT_EXTERNAL_INSTALLER;
Jeff Sharkey5bf9d722019-01-23 23:52:11 -0700363 } else if (arg.equals("--mount-external-legacy")) {
364 mMountExternal = Zygote.MOUNT_EXTERNAL_LEGACY;
Chris Wailes2be26262019-01-11 16:14:43 -0800365 } else if (arg.equals("--query-abi-list")) {
366 mAbiListQuery = true;
367 } else if (arg.equals("--get-pid")) {
368 mPidQuery = true;
369 } else if (arg.startsWith("--instruction-set=")) {
370 mInstructionSet = arg.substring(arg.indexOf('=') + 1);
371 } else if (arg.startsWith("--app-data-dir=")) {
372 mAppDataDir = arg.substring(arg.indexOf('=') + 1);
373 } else if (arg.equals("--preload-app")) {
374 mPreloadApp = args[++curArg];
375 } else if (arg.equals("--preload-package")) {
376 mPreloadPackage = args[++curArg];
377 mPreloadPackageLibs = args[++curArg];
378 mPreloadPackageLibFileName = args[++curArg];
379 mPreloadPackageCacheKey = args[++curArg];
380 } else if (arg.equals("--preload-default")) {
381 mPreloadDefault = true;
382 expectRuntimeArgs = false;
383 } else if (arg.equals("--start-child-zygote")) {
384 mStartChildZygote = true;
385 } else if (arg.equals("--set-api-blacklist-exemptions")) {
386 // consume all remaining args; this is a stand-alone command, never included
387 // with the regular fork command.
388 mApiBlacklistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length);
389 curArg = args.length;
390 expectRuntimeArgs = false;
391 } else if (arg.startsWith("--hidden-api-log-sampling-rate=")) {
392 String rateStr = arg.substring(arg.indexOf('=') + 1);
393 try {
394 mHiddenApiAccessLogSampleRate = Integer.parseInt(rateStr);
395 } catch (NumberFormatException nfe) {
396 throw new IllegalArgumentException(
397 "Invalid log sampling rate: " + rateStr, nfe);
398 }
399 expectRuntimeArgs = false;
Andrei Oneae8e150d2019-02-18 18:27:11 +0000400 } else if (arg.startsWith("--hidden-api-statslog-sampling-rate=")) {
401 String rateStr = arg.substring(arg.indexOf('=') + 1);
402 try {
403 mHiddenApiAccessStatslogSampleRate = Integer.parseInt(rateStr);
404 } catch (NumberFormatException nfe) {
405 throw new IllegalArgumentException(
406 "Invalid statslog sampling rate: " + rateStr, nfe);
407 }
408 expectRuntimeArgs = false;
Chris Wailes2be26262019-01-11 16:14:43 -0800409 } else if (arg.startsWith("--package-name=")) {
410 if (mPackageName != null) {
411 throw new IllegalArgumentException("Duplicate arg specified");
412 }
413 mPackageName = arg.substring(arg.indexOf('=') + 1);
414 } else if (arg.startsWith("--packages-for-uid=")) {
415 mPackagesForUid = arg.substring(arg.indexOf('=') + 1).split(",");
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800416 } else if (arg.startsWith("--sandbox-id=")) {
417 if (mSandboxId != null) {
418 throw new IllegalArgumentException("Duplicate arg specified");
419 }
420 mSandboxId = arg.substring(arg.indexOf('=') + 1);
Chris Wailes7e797b62019-02-22 18:29:22 -0800421 } else if (arg.startsWith("--usap-pool-enabled=")) {
422 mUsapPoolStatusSpecified = true;
423 mUsapPoolEnabled = Boolean.parseBoolean(arg.substring(arg.indexOf('=') + 1));
Chris Wailesdb132a32019-02-20 10:49:27 -0800424 expectRuntimeArgs = false;
Chris Wailes2be26262019-01-11 16:14:43 -0800425 } else {
426 break;
427 }
428 }
429
430 if (mAbiListQuery || mPidQuery) {
431 if (args.length - curArg > 0) {
432 throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
433 }
434 } else if (mPreloadPackage != null) {
435 if (args.length - curArg > 0) {
436 throw new IllegalArgumentException(
437 "Unexpected arguments after --preload-package.");
438 }
439 } else if (mPreloadApp != null) {
440 if (args.length - curArg > 0) {
441 throw new IllegalArgumentException(
442 "Unexpected arguments after --preload-app.");
443 }
444 } else if (expectRuntimeArgs) {
445 if (!seenRuntimeArgs) {
446 throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
447 }
448
449 mRemainingArgs = new String[args.length - curArg];
450 System.arraycopy(args, curArg, mRemainingArgs, 0, mRemainingArgs.length);
451 }
452
453 if (mStartChildZygote) {
454 boolean seenChildSocketArg = false;
455 for (String arg : mRemainingArgs) {
456 if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
457 seenChildSocketArg = true;
458 break;
459 }
460 }
461 if (!seenChildSocketArg) {
462 throw new IllegalArgumentException("--start-child-zygote specified "
463 + "without " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG);
464 }
465 }
466 }
467}