• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.os;
18 
19 import static android.system.OsConstants.O_CLOEXEC;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.compat.annotation.ChangeId;
24 import android.compat.annotation.Disabled;
25 import android.compat.annotation.EnabledAfter;
26 import android.content.Context;
27 import android.content.pm.ApplicationInfo;
28 import android.content.pm.ProcessInfo;
29 import android.net.Credentials;
30 import android.net.LocalServerSocket;
31 import android.net.LocalSocket;
32 import android.os.Build;
33 import android.os.FactoryTest;
34 import android.os.IVold;
35 import android.os.Process;
36 import android.os.RemoteException;
37 import android.os.ServiceManager;
38 import android.os.SystemProperties;
39 import android.os.Trace;
40 import android.provider.DeviceConfig;
41 import android.system.ErrnoException;
42 import android.system.Os;
43 import android.util.Log;
44 
45 import com.android.internal.compat.IPlatformCompat;
46 import com.android.internal.net.NetworkUtilsInternal;
47 
48 import dalvik.annotation.optimization.CriticalNative;
49 import dalvik.annotation.optimization.FastNative;
50 import dalvik.system.ZygoteHooks;
51 
52 import libcore.io.IoUtils;
53 
54 import java.io.ByteArrayOutputStream;
55 import java.io.DataOutputStream;
56 import java.io.FileDescriptor;
57 import java.io.IOException;
58 
59 /** @hide */
60 public final class Zygote {
61     /*
62     * Bit values for "runtimeFlags" argument.  The definitions are duplicated
63     * in the native code.
64     */
65 
66     /** enable debugging over JDWP */
67     public static final int DEBUG_ENABLE_JDWP   = 1;
68     /** enable JNI checks */
69     public static final int DEBUG_ENABLE_CHECKJNI   = 1 << 1;
70     /** enable Java programming language "assert" statements */
71     public static final int DEBUG_ENABLE_ASSERT     = 1 << 2;
72     /** disable the AOT compiler and JIT */
73     public static final int DEBUG_ENABLE_SAFEMODE   = 1 << 3;
74     /** Enable logging of third-party JNI activity. */
75     public static final int DEBUG_ENABLE_JNI_LOGGING = 1 << 4;
76     /** Force generation of native debugging information. */
77     public static final int DEBUG_GENERATE_DEBUG_INFO = 1 << 5;
78     /** Always use JIT-ed code. */
79     public static final int DEBUG_ALWAYS_JIT = 1 << 6;
80     /** Make the code native debuggable by turning off some optimizations. */
81     public static final int DEBUG_NATIVE_DEBUGGABLE = 1 << 7;
82     /** Make the code Java debuggable by turning off some optimizations. */
83     public static final int DEBUG_JAVA_DEBUGGABLE = 1 << 8;
84 
85     /** Turn off the verifier. */
86     public static final int DISABLE_VERIFIER = 1 << 9;
87     /** Only use oat files located in /system. Otherwise use dex/jar/apk . */
88     public static final int ONLY_USE_SYSTEM_OAT_FILES = 1 << 10;
89     /** Force generation of native debugging information for backtraces. */
90     public static final int DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 11;
91     /**
92      * Hidden API access restrictions. This is a mask for bits representing the API enforcement
93      * policy, defined by {@code @ApplicationInfo.HiddenApiEnforcementPolicy}.
94      */
95     public static final int API_ENFORCEMENT_POLICY_MASK = (1 << 12) | (1 << 13);
96     /**
97      * Bit shift for use with {@link #API_ENFORCEMENT_POLICY_MASK}.
98      *
99      * (flags & API_ENFORCEMENT_POLICY_MASK) >> API_ENFORCEMENT_POLICY_SHIFT gives
100      * {@link ApplicationInfo.HiddenApiEnforcementPolicy} values.
101      */
102     public static final int API_ENFORCEMENT_POLICY_SHIFT =
103             Integer.numberOfTrailingZeros(API_ENFORCEMENT_POLICY_MASK);
104     /**
105      * Enable system server ART profiling.
106      */
107     public static final int PROFILE_SYSTEM_SERVER = 1 << 14;
108 
109     /**
110      * Enable profiling from shell.
111      */
112     public static final int PROFILE_FROM_SHELL = 1 << 15;
113 
114     /*
115      * Enable using the ART app image startup cache
116      */
117     public static final int USE_APP_IMAGE_STARTUP_CACHE = 1 << 16;
118 
119     /**
120      * When set, application specified signal handlers are not chained (i.e, ignored)
121      * by the runtime.
122      *
123      * Used for debugging only. Usage: set debug.ignoreappsignalhandler to 1.
124      */
125     public static final int DEBUG_IGNORE_APP_SIGNAL_HANDLER = 1 << 17;
126 
127     /**
128      * Disable runtime access to {@link android.annotation.TestApi} annotated members.
129      *
130      * <p>This only takes effect if Hidden API access restrictions are enabled as well.
131      */
132     public static final int DISABLE_TEST_API_ENFORCEMENT_POLICY = 1 << 18;
133 
134     public static final int MEMORY_TAG_LEVEL_MASK = (1 << 19) | (1 << 20);
135 
136     public static final int MEMORY_TAG_LEVEL_NONE = 0;
137 
138     /**
139      * Enable pointer tagging in this process.
140      * Tags are checked during memory deallocation, but not on access.
141      * TBI stands for Top-Byte-Ignore, an ARM CPU feature.
142      * {@link https://developer.arm.com/docs/den0024/latest/the-memory-management-unit/translation-table-configuration/virtual-address-tagging}
143      */
144     public static final int MEMORY_TAG_LEVEL_TBI = 1 << 19;
145 
146     /**
147      * Enable asynchronous memory tag checks in this process.
148      */
149     public static final int MEMORY_TAG_LEVEL_ASYNC = 2 << 19;
150 
151     /**
152      * Enable synchronous memory tag checks in this process.
153      */
154     public static final int MEMORY_TAG_LEVEL_SYNC = 3 << 19;
155 
156     /**
157      * A two-bit field for GWP-ASan level of this process. See the possible values below.
158      */
159     public static final int GWP_ASAN_LEVEL_MASK = (1 << 21) | (1 << 22);
160 
161     /**
162      * Disable GWP-ASan in this process.
163      * GWP-ASan is a low-overhead memory bug detector using guard pages on a small
164      * subset of heap allocations.
165      */
166     public static final int GWP_ASAN_LEVEL_NEVER = 0 << 21;
167 
168     /**
169      * Enable GWP-ASan in this process with a small sampling rate.
170      * With approx. 1% chance GWP-ASan will be activated and apply its protection
171      * to a small subset of heap allocations.
172      * Otherwise (~99% chance) this process is unaffected.
173      */
174     public static final int GWP_ASAN_LEVEL_LOTTERY = 1 << 21;
175 
176     /**
177      * Always enable GWP-ASan in this process.
178      * GWP-ASan is activated unconditionally (but still, only a small subset of
179      * allocations is protected).
180      */
181     public static final int GWP_ASAN_LEVEL_ALWAYS = 2 << 21;
182 
183     /**
184      * GWP-ASan's `gwpAsanMode` manifest flag was unspecified. Currently, this
185      * means GWP_ASAN_LEVEL_LOTTERY for system apps, and GWP_ASAN_LEVEL_NONE for
186      * non-system apps.
187      */
188     public static final int GWP_ASAN_LEVEL_DEFAULT = 3 << 21;
189 
190     /** Enable automatic zero-initialization of native heap memory allocations. */
191     public static final int NATIVE_HEAP_ZERO_INIT_ENABLED = 1 << 23;
192 
193     /**
194      * Enable profiling from system services. This loads profiling related plugins in ART.
195      */
196     public static final int PROFILEABLE = 1 << 24;
197 
198     /**
199      * Enable ptrace.  This is enabled on eng, if the app is debuggable, or if
200      * the persist.debug.ptrace.enabled property is set.
201      */
202     public static final int DEBUG_ENABLE_PTRACE = 1 << 25;
203 
204     /** No external storage should be mounted. */
205     public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE;
206     /** Default external storage should be mounted. */
207     public static final int MOUNT_EXTERNAL_DEFAULT = IVold.REMOUNT_MODE_DEFAULT;
208     /**
209      * Mount mode for package installers which should give them access to
210      * all obb dirs in addition to their package sandboxes
211      */
212     public static final int MOUNT_EXTERNAL_INSTALLER = IVold.REMOUNT_MODE_INSTALLER;
213     /** The lower file system should be bind mounted directly on external storage */
214     public static final int MOUNT_EXTERNAL_PASS_THROUGH = IVold.REMOUNT_MODE_PASS_THROUGH;
215 
216     /** Use the regular scoped storage filesystem, but Android/ should be writable.
217      * Used to support the applications hosting DownloadManager and the MTP server.
218      */
219     public static final int MOUNT_EXTERNAL_ANDROID_WRITABLE = IVold.REMOUNT_MODE_ANDROID_WRITABLE;
220 
221     /** Number of bytes sent to the Zygote over USAP pipes or the pool event FD */
222     static final int USAP_MANAGEMENT_MESSAGE_BYTES = 8;
223 
224     /** Make the new process have top application priority. */
225     public static final String START_AS_TOP_APP_ARG = "--is-top-app";
226 
227     /** List of packages with the same uid, and its app data info: volume uuid and inode. */
228     public static final String PKG_DATA_INFO_MAP = "--pkg-data-info-map";
229 
230     /** List of allowlisted packages and its app data info: volume uuid and inode. */
231     public static final String ALLOWLISTED_DATA_INFO_MAP = "--allowlisted-data-info-map";
232 
233     /** Bind mount app storage dirs to lower fs not via fuse */
234     public static final String BIND_MOUNT_APP_STORAGE_DIRS = "--bind-mount-storage-dirs";
235 
236     /** Bind mount app storage dirs to lower fs not via fuse */
237     public static final String BIND_MOUNT_APP_DATA_DIRS = "--bind-mount-data-dirs";
238 
239     /** Bind the system properties to an alternate set, for appcompat reasons */
240     public static final String BIND_MOUNT_SYSPROP_OVERRIDES = "--bind-mount-sysprop-overrides";
241 
242     /**
243      * An extraArg passed when a zygote process is forking a child-zygote, specifying a name
244      * in the abstract socket namespace. This socket name is what the new child zygote
245      * should listen for connections on.
246      */
247     public static final String CHILD_ZYGOTE_SOCKET_NAME_ARG = "--zygote-socket=";
248 
249     /**
250      * An extraArg passed when a zygote process is forking a child-zygote, specifying the
251      * requested ABI for the child Zygote.
252      */
253     public static final String CHILD_ZYGOTE_ABI_LIST_ARG = "--abi-list=";
254 
255     /**
256      * An extraArg passed when a zygote process is forking a child-zygote, specifying the
257      * start of the UID range the children of the Zygote may setuid()/setgid() to. This
258      * will be enforced with a seccomp filter.
259      */
260     public static final String CHILD_ZYGOTE_UID_RANGE_START = "--uid-range-start=";
261 
262     /**
263      * An extraArg passed when a zygote process is forking a child-zygote, specifying the
264      * end of the UID range the children of the Zygote may setuid()/setgid() to. This
265      * will be enforced with a seccomp filter.
266      */
267     public static final String CHILD_ZYGOTE_UID_RANGE_END = "--uid-range-end=";
268 
269     private static final String TAG = "Zygote";
270 
271     /** Prefix prepended to socket names created by init */
272     private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
273 
274     /**
275      * The duration to wait before re-checking Zygote related system properties.
276      *
277      * One minute in milliseconds.
278      */
279     public static final long PROPERTY_CHECK_INTERVAL = 60000;
280 
281     /**
282      * @hide for internal use only
283      */
284     public static final int SOCKET_BUFFER_SIZE = 256;
285 
286     /**
287      * @hide for internal use only
288      */
289     private static final int PRIORITY_MAX = -20;
290 
291     /** a prototype instance for a future List.toArray() */
292     static final int[][] INT_ARRAY_2D = new int[0][0];
293 
294     /**
295      * @hide for internal use only.
296      */
297     public static final String PRIMARY_SOCKET_NAME = "zygote";
298 
299     /**
300      * @hide for internal use only.
301      */
302     public static final String SECONDARY_SOCKET_NAME = "zygote_secondary";
303 
304     /**
305      * @hide for internal use only
306      */
307     public static final String USAP_POOL_PRIMARY_SOCKET_NAME = "usap_pool_primary";
308 
309     /**
310      * @hide for internal use only
311      */
312     public static final String USAP_POOL_SECONDARY_SOCKET_NAME = "usap_pool_secondary";
313 
Zygote()314     private Zygote() {}
315 
containsInetGid(int[] gids)316     private static boolean containsInetGid(int[] gids) {
317         for (int i = 0; i < gids.length; i++) {
318             if (gids[i] == android.os.Process.INET_GID) return true;
319         }
320         return false;
321     }
322 
323     /**
324      * Forks a new VM instance.  The current VM must have been started
325      * with the -Xzygote flag. <b>NOTE: new instance keeps all
326      * root capabilities. The new process is expected to call capset()</b>.
327      *
328      * @param uid the UNIX uid that the new process should setuid() to after
329      * fork()ing and and before spawning any threads.
330      * @param gid the UNIX gid that the new process should setgid() to after
331      * fork()ing and and before spawning any threads.
332      * @param gids null-ok; a list of UNIX gids that the new process should
333      * setgroups() to after fork and before spawning any threads.
334      * @param runtimeFlags bit flags that enable ART features.
335      * @param rlimits null-ok an array of rlimit tuples, with the second
336      * dimension having a length of 3 and representing
337      * (resource, rlim_cur, rlim_max). These are set via the posix
338      * setrlimit(2) call.
339      * @param seInfo null-ok a string specifying SELinux information for
340      * the new process.
341      * @param niceName null-ok a string specifying the process name.
342      * @param fdsToClose an array of ints, holding one or more POSIX
343      * file descriptor numbers that are to be closed by the child
344      * (and replaced by /dev/null) after forking.  An integer value
345      * of -1 in any entry in the array means "ignore this one".
346      * @param fdsToIgnore null-ok an array of ints, either null or holding
347      * one or more POSIX file descriptor numbers that are to be ignored
348      * in the file descriptor table check.
349      * @param startChildZygote if true, the new child process will itself be a
350      * new zygote process.
351      * @param instructionSet null-ok the instruction set to use.
352      * @param appDataDir null-ok the data directory of the app.
353      * @param isTopApp true if the process is for top (high priority) application.
354      * @param pkgDataInfoList A list that stores related packages and its app data
355      * info: volume uuid and inode.
356      * @param allowlistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps.
357      * @param bindMountAppDataDirs  True if the zygote needs to mount data dirs.
358      * @param bindMountAppStorageDirs  True if the zygote needs to mount storage dirs.
359      * @param bindMountSyspropOverrides True if the zygote needs to mount the override system
360      *                                  properties
361      *
362      * @return 0 if this is the child, pid of the child
363      * if this is the parent, or -1 on error.
364      */
forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs, boolean bindMountSyspropOverrides)365     static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
366             int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
367             int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
368             boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList,
369             boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs,
370             boolean bindMountSyspropOverrides) {
371         ZygoteHooks.preFork();
372 
373         int pid = nativeForkAndSpecialize(
374                 uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
375                 fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp,
376                 pkgDataInfoList, allowlistedDataInfoList, bindMountAppDataDirs,
377                 bindMountAppStorageDirs, bindMountSyspropOverrides);
378         if (pid == 0) {
379             // Note that this event ends at the end of handleChildProc,
380             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
381 
382             // If no GIDs were specified, don't make any permissions changes based on groups.
383             if (gids != null && gids.length > 0) {
384                 NetworkUtilsInternal.setAllowNetworkingForProcess(containsInetGid(gids));
385             }
386         }
387 
388         // Set the Java Language thread priority to the default value for new apps.
389         Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
390 
391         ZygoteHooks.postForkCommon();
392         return pid;
393     }
394 
nativeForkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs, boolean bindMountSyspropOverrides)395     private static native int nativeForkAndSpecialize(int uid, int gid, int[] gids,
396             int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
397             int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet,
398             String appDataDir, boolean isTopApp, String[] pkgDataInfoList,
399             String[] allowlistedDataInfoList, boolean bindMountAppDataDirs,
400             boolean bindMountAppStorageDirs, boolean bindMountSyspropOverrides);
401 
402     /**
403      * Specialize an unspecialized app process.  The current VM must have been started
404      * with the -Xzygote flag.
405      *
406      * @param uid  The UNIX uid that the new process should setuid() to before spawning any threads
407      * @param gid  The UNIX gid that the new process should setgid() to before spawning any threads
408      * @param gids null-ok;  A list of UNIX gids that the new process should
409      * setgroups() to before spawning any threads
410      * @param runtimeFlags  Bit flags that enable ART features
411      * @param rlimits null-ok  An array of rlimit tuples, with the second
412      * dimension having a length of 3 and representing
413      * (resource, rlim_cur, rlim_max). These are set via the posix
414      * setrlimit(2) call.
415      * @param seInfo null-ok  A string specifying SELinux information for
416      * the new process.
417      * @param niceName null-ok  A string specifying the process name.
418      * @param startChildZygote  If true, the new child process will itself be a
419      * new zygote process.
420      * @param instructionSet null-ok  The instruction set to use.
421      * @param appDataDir null-ok  The data directory of the app.
422      * @param isTopApp  True if the process is for top (high priority) application.
423      * @param pkgDataInfoList A list that stores related packages and its app data
424      * volume uuid and CE dir inode. For example, pkgDataInfoList = [app_a_pkg_name,
425      * app_a_data_volume_uuid, app_a_ce_inode, app_b_pkg_name, app_b_data_volume_uuid,
426      * app_b_ce_inode, ...];
427      * @param allowlistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps.
428      * @param bindMountAppDataDirs  True if the zygote needs to mount data dirs.
429      * @param bindMountAppStorageDirs  True if the zygote needs to mount storage dirs.
430      * @param bindMountSyspropOverrides True if the zygote needs to mount the override system
431      *                                  properties
432      */
specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs, boolean bindMountSyspropOverrides)433     private static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags,
434             int[][] rlimits, int mountExternal, String seInfo, String niceName,
435             boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
436             String[] pkgDataInfoList, String[] allowlistedDataInfoList,
437             boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs,
438             boolean bindMountSyspropOverrides) {
439         nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo,
440                 niceName, startChildZygote, instructionSet, appDataDir, isTopApp,
441                 pkgDataInfoList, allowlistedDataInfoList,
442                 bindMountAppDataDirs, bindMountAppStorageDirs, bindMountSyspropOverrides);
443 
444         // Note that this event ends at the end of handleChildProc.
445         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
446 
447         if (gids != null && gids.length > 0) {
448             NetworkUtilsInternal.setAllowNetworkingForProcess(containsInetGid(gids));
449         }
450 
451         // Set the Java Language thread priority to the default value for new apps.
452         Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
453 
454         /*
455          * This is called here (instead of after the fork but before the specialize) to maintain
456          * consistancy with the code paths for forkAndSpecialize.
457          *
458          * TODO (chriswailes): Look into moving this to immediately after the fork.
459          */
460         ZygoteHooks.postForkCommon();
461     }
462 
nativeSpecializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs, boolean bindMountSyspropOverrides)463     private static native void nativeSpecializeAppProcess(int uid, int gid, int[] gids,
464             int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
465             boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
466             String[] pkgDataInfoList, String[] allowlistedDataInfoList,
467             boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs,
468             boolean bindMountSyspropOverrides);
469 
470     /**
471      * Called to do any initialization before starting an application.
472      */
nativePreApplicationInit()473     static native void nativePreApplicationInit();
474 
475     /**
476      * Special method to start the system server process. In addition to the
477      * common actions performed in forkAndSpecialize, the pid of the child
478      * process is recorded such that the death of the child process will cause
479      * zygote to exit.
480      *
481      * @param uid the UNIX uid that the new process should setuid() to after
482      * fork()ing and and before spawning any threads.
483      * @param gid the UNIX gid that the new process should setgid() to after
484      * fork()ing and and before spawning any threads.
485      * @param gids null-ok; a list of UNIX gids that the new process should
486      * setgroups() to after fork and before spawning any threads.
487      * @param runtimeFlags bit flags that enable ART features.
488      * @param rlimits null-ok an array of rlimit tuples, with the second
489      * dimension having a length of 3 and representing
490      * (resource, rlim_cur, rlim_max). These are set via the posix
491      * setrlimit(2) call.
492      * @param permittedCapabilities argument for setcap()
493      * @param effectiveCapabilities argument for setcap()
494      *
495      * @return 0 if this is the child, pid of the child
496      * if this is the parent, or -1 on error.
497      */
forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities)498     static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
499             int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
500         ZygoteHooks.preFork();
501 
502         int pid = nativeForkSystemServer(
503                 uid, gid, gids, runtimeFlags, rlimits,
504                 permittedCapabilities, effectiveCapabilities);
505 
506         // Set the Java Language thread priority to the default value for new apps.
507         Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
508 
509         ZygoteHooks.postForkCommon();
510         return pid;
511     }
512 
nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities)513     private static native int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
514             int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
515 
516     /**
517      * Lets children of the zygote inherit open file descriptors to this path.
518      */
nativeAllowFileAcrossFork(String path)519     protected static native void nativeAllowFileAcrossFork(String path);
520 
521     /**
522      * Lets children of the zygote inherit open file descriptors that belong to the
523      * ApplicationInfo that is passed in.
524      *
525      * @param appInfo ApplicationInfo of the application
526      */
allowAppFilesAcrossFork(ApplicationInfo appInfo)527     static void allowAppFilesAcrossFork(ApplicationInfo appInfo) {
528         for (String path : appInfo.getAllApkPaths()) {
529             Zygote.nativeAllowFileAcrossFork(path);
530         }
531     }
532 
533     /**
534      * Scans file descriptors in /proc/self/fd/, stores their metadata from readlink(2)/stat(2) when
535      * available. Saves this information in a global on native side, to be used by subsequent call
536      * to allowFilesOpenedByPreload(). Fatally fails if the FDs are of unsupported type and are not
537      * explicitly allowed. Ignores repeated invocations.
538      *
539      * Inspecting the FDs is more permissive than in forkAndSpecialize() because preload is invoked
540      * earlier and hence needs to allow a few open sockets. The checks in forkAndSpecialize()
541      * enforce that these sockets are closed when forking.
542      */
markOpenedFilesBeforePreload()543     static void markOpenedFilesBeforePreload() {
544         nativeMarkOpenedFilesBeforePreload();
545     }
546 
nativeMarkOpenedFilesBeforePreload()547     private static native void nativeMarkOpenedFilesBeforePreload();
548 
549     /**
550      * By scanning /proc/self/fd/ determines file descriptor numbers in this process opened since
551      * the first call to markOpenedFilesBeforePreload(). These FDs are treated as 'owned' by the
552      * custom preload of the App Zygote - the app is responsible for not sharing data with its other
553      * processes using these FDs, including by lseek(2). File descriptor types and file names are
554      * not checked. Changes in FDs recorded by markOpenedFilesBeforePreload() are not expected and
555      * kill the current process.
556      */
allowFilesOpenedByPreload()557     static void allowFilesOpenedByPreload() {
558         nativeAllowFilesOpenedByPreload();
559     }
560 
nativeAllowFilesOpenedByPreload()561     private static native void nativeAllowFilesOpenedByPreload();
562 
563     /**
564      * Installs a seccomp filter that limits setresuid()/setresgid() to the passed-in range
565      * @param uidGidMin The smallest allowed uid/gid
566      * @param uidGidMax The largest allowed uid/gid
567      */
nativeInstallSeccompUidGidFilter(int uidGidMin, int uidGidMax)568     native protected static void nativeInstallSeccompUidGidFilter(int uidGidMin, int uidGidMax);
569 
570     /**
571      * Initialize the native state of the Zygote.  This inclues
572      *   - Fetching socket FDs from the environment
573      *   - Initializing security properties
574      *   - Unmounting storage as appropriate
575      *   - Loading necessary performance profile information
576      *
577      * @param isPrimary  True if this is the zygote process, false if it is zygote_secondary
578      */
initNativeState(boolean isPrimary)579     static void initNativeState(boolean isPrimary) {
580         nativeInitNativeState(isPrimary);
581     }
582 
nativeInitNativeState(boolean isPrimary)583     protected static native void nativeInitNativeState(boolean isPrimary);
584 
585     /**
586      * Returns the raw string value of a system property.
587      *
588      * Note that Device Config is not available without an application so SystemProperties is used
589      * instead.
590      *
591      * TODO (chriswailes): Cache the system property location in native code and then write a JNI
592      *                     function to fetch it.
593      */
getConfigurationProperty(String propertyName, String defaultValue)594     public static String getConfigurationProperty(String propertyName, String defaultValue) {
595         return SystemProperties.get(
596                 String.join(".",
597                         "persist.device_config",
598                         DeviceConfig.NAMESPACE_RUNTIME_NATIVE,
599                         propertyName),
600                 defaultValue);
601     }
602 
emptyUsapPool()603     static void emptyUsapPool() {
604         nativeEmptyUsapPool();
605     }
606 
nativeEmptyUsapPool()607     private static native void nativeEmptyUsapPool();
608 
609     /**
610      * Returns the value of a system property converted to a boolean using specific logic.
611      *
612      * Note that Device Config is not available without an application so SystemProperties is used
613      * instead.
614      *
615      * @see SystemProperties#getBoolean
616      *
617      * TODO (chriswailes): Cache the system property location in native code and then write a JNI
618      *                     function to fetch it.
619      * TODO (chriswailes): Move into ZygoteConfig.java once the necessary CL lands (go/ag/6580627)
620      */
getConfigurationPropertyBoolean( String propertyName, Boolean defaultValue)621     public static boolean getConfigurationPropertyBoolean(
622             String propertyName, Boolean defaultValue) {
623         return SystemProperties.getBoolean(
624                 String.join(".",
625                         "persist.device_config",
626                         DeviceConfig.NAMESPACE_RUNTIME_NATIVE,
627                         propertyName),
628                 defaultValue);
629     }
630 
631     /**
632      * @return Number of unspecialized app processes currently in the pool
633      */
getUsapPoolCount()634     static int getUsapPoolCount() {
635         return nativeGetUsapPoolCount();
636     }
637 
nativeGetUsapPoolCount()638     private static native int nativeGetUsapPoolCount();
639 
640     /**
641      * @return The event FD used for communication between the signal handler and the ZygoteServer
642      *         poll loop
643      */
getUsapPoolEventFD()644     static FileDescriptor getUsapPoolEventFD() {
645         FileDescriptor fd = new FileDescriptor();
646         fd.setInt$(nativeGetUsapPoolEventFD());
647 
648         return fd;
649     }
650 
nativeGetUsapPoolEventFD()651     private static native int nativeGetUsapPoolEventFD();
652 
653     /**
654      * Fork a new unspecialized app process from the zygote. Adds the Usap to the native
655      * Usap table.
656      *
657      * @param usapPoolSocket  The server socket the USAP will call accept on
658      * @param sessionSocketRawFDs  Anonymous session sockets that are currently open.
659      *         These are closed in the child.
660      * @param isPriorityFork Raise the initial process priority level because this is on the
661      *         critical path for application startup.
662      * @return In the child process, this returns a Runnable that waits for specialization
663      *         info to start an app process. In the sygote/parent process this returns null.
664      */
forkUsap(LocalServerSocket usapPoolSocket, int[] sessionSocketRawFDs, boolean isPriorityFork)665     static @Nullable Runnable forkUsap(LocalServerSocket usapPoolSocket,
666                                        int[] sessionSocketRawFDs,
667                                        boolean isPriorityFork) {
668         FileDescriptor readFD;
669         FileDescriptor writeFD;
670 
671         try {
672             FileDescriptor[] pipeFDs = Os.pipe2(O_CLOEXEC);
673             readFD = pipeFDs[0];
674             writeFD = pipeFDs[1];
675         } catch (ErrnoException errnoEx) {
676             throw new IllegalStateException("Unable to create USAP pipe.", errnoEx);
677         }
678 
679         int pid = nativeForkApp(readFD.getInt$(), writeFD.getInt$(),
680                                 sessionSocketRawFDs, /*argsKnown=*/ false, isPriorityFork);
681         if (pid == 0) {
682             IoUtils.closeQuietly(readFD);
683             return childMain(null, usapPoolSocket, writeFD);
684         } else if (pid == -1) {
685             // Fork failed.
686             return null;
687         } else {
688             // readFD will be closed by the native code. See removeUsapTableEntry();
689             IoUtils.closeQuietly(writeFD);
690             nativeAddUsapTableEntry(pid, readFD.getInt$());
691             return null;
692         }
693     }
694 
nativeForkApp(int readPipeFD, int writePipeFD, int[] sessionSocketRawFDs, boolean argsKnown, boolean isPriorityFork)695     private static native int nativeForkApp(int readPipeFD,
696                                             int writePipeFD,
697                                             int[] sessionSocketRawFDs,
698                                             boolean argsKnown,
699                                             boolean isPriorityFork);
700 
701     /**
702      * Add an entry for a new Usap to the table maintained in native code.
703      */
704     @CriticalNative
nativeAddUsapTableEntry(int pid, int readPipeFD)705     private static native void nativeAddUsapTableEntry(int pid, int readPipeFD);
706 
707     /**
708      * Fork a new app process from the zygote. argBuffer contains a fork command that
709      * request neither a child zygote, nor a wrapped process. Continue to accept connections
710      * on the specified socket, use those to refill argBuffer, and continue to process
711      * sufficiently simple fork requests. We presume that the only open file descriptors
712      * requiring special treatment are the session socket embedded in argBuffer, and
713      * zygoteSocket.
714      * @param argBuffer containing initial command and the connected socket from which to
715      *         read more
716      * @param zygoteSocket socket from which to obtain new connections when current argBuffer
717      *         one is disconnected
718      * @param expectedUId Uid of peer for initial requests. Subsequent requests from a different
719      *               peer will cause us to return rather than perform the requested fork.
720      * @param minUid Minimum Uid enforced for all but first fork request. The caller checks
721      *               the Uid policy for the initial request.
722      * @param firstNiceName name of first created process. Used for error reporting only.
723      * @return A Runnable in each child process, null in the parent.
724      * If this returns in then argBuffer still contains a command needing to be executed.
725      */
forkSimpleApps(@onNull ZygoteCommandBuffer argBuffer, @NonNull FileDescriptor zygoteSocket, int expectedUid, int minUid, @Nullable String firstNiceName)726     static @Nullable Runnable forkSimpleApps(@NonNull ZygoteCommandBuffer argBuffer,
727                                              @NonNull FileDescriptor zygoteSocket,
728                                              int expectedUid,
729                                              int minUid,
730                                              @Nullable String firstNiceName) {
731         boolean in_child =
732                 argBuffer.forkRepeatedly(zygoteSocket, expectedUid, minUid, firstNiceName);
733         if (in_child) {
734             return childMain(argBuffer, /*usapPoolSocket=*/null, /*writePipe=*/null);
735         } else {
736             return null;
737         }
738     }
739 
740     /**
741      * Specialize the current process into one described by argBuffer or the command read from
742      * usapPoolSocket. Exactly one of those must be null. If we are given an argBuffer, we close
743      * it. Used both for a specializing a USAP process, and for process creation without USAPs.
744      * In both cases, we specialize the process after first returning to Java code.
745      *
746      * @param writePipe  The write end of the reporting pipe used to communicate with the poll loop
747      *                   of the ZygoteServer.
748      * @return A runnable oject representing the new application.
749      */
childMain(@ullable ZygoteCommandBuffer argBuffer, @Nullable LocalServerSocket usapPoolSocket, FileDescriptor writePipe)750     private static Runnable childMain(@Nullable ZygoteCommandBuffer argBuffer,
751                                       @Nullable LocalServerSocket usapPoolSocket,
752                                       FileDescriptor writePipe) {
753         final int pid = Process.myPid();
754 
755         DataOutputStream usapOutputStream = null;
756         ZygoteArguments args = null;
757 
758         LocalSocket sessionSocket = null;
759         if (argBuffer == null) {
760             // Read arguments from usapPoolSocket instead.
761 
762             Process.setArgV0(Process.is64Bit() ? "usap64" : "usap32");
763 
764             // Change the priority to max before calling accept so we can respond to new
765             // specialization requests as quickly as possible.  This will be reverted to the
766             // default priority in the native specialization code.
767             boostUsapPriority();
768 
769             while (true) {
770                 ZygoteCommandBuffer tmpArgBuffer = null;
771                 try {
772                     sessionSocket = usapPoolSocket.accept();
773                     // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool.
774                     // This is safe from a race condition because the pool is only flushed after
775                     // the SystemServer changes its internal state to stop using the USAP pool.
776                     blockSigTerm();
777 
778                     usapOutputStream =
779                             new DataOutputStream(sessionSocket.getOutputStream());
780                     Credentials peerCredentials = sessionSocket.getPeerCredentials();
781                     tmpArgBuffer = new ZygoteCommandBuffer(sessionSocket);
782                     args = ZygoteArguments.getInstance(tmpArgBuffer);
783                     applyUidSecurityPolicy(args, peerCredentials);
784                     // TODO (chriswailes): Should this only be run for debug builds?
785                     validateUsapCommand(args);
786                     break;
787                 } catch (Exception ex) {
788                     Log.e("USAP", ex.getMessage());
789                 }
790                 // Re-enable SIGTERM so the USAP can be flushed from the pool if necessary.
791                 unblockSigTerm();
792                 IoUtils.closeQuietly(sessionSocket);
793                 IoUtils.closeQuietly(tmpArgBuffer);
794             }
795         } else {
796             // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool.
797             blockSigTerm();
798             try {
799                 args = ZygoteArguments.getInstance(argBuffer);
800             } catch (Exception ex) {
801                 Log.e("AppStartup", ex.getMessage());
802                 throw new AssertionError("Failed to parse application start command", ex);
803             }
804             // peerCredentials were checked in parent.
805         }
806         if (args == null) {
807             throw new AssertionError("Empty command line");
808         }
809         try {
810             // SIGTERM is blocked here.  This prevents a USAP that is specializing from being
811             // killed during a pool flush.
812 
813             applyDebuggerSystemProperty(args);
814 
815             int[][] rlimits = null;
816 
817             if (args.mRLimits != null) {
818                 rlimits = args.mRLimits.toArray(INT_ARRAY_2D);
819             }
820 
821             if (argBuffer == null) {
822                 // This must happen before the SELinux policy for this process is
823                 // changed when specializing.
824                 try {
825                     // Used by ZygoteProcess.zygoteSendArgsAndGetResult to fill in a
826                     // Process.ProcessStartResult object.
827                     usapOutputStream.writeInt(pid);
828                 } catch (IOException ioEx) {
829                     Log.e("USAP", "Failed to write response to session socket: "
830                             + ioEx.getMessage());
831                     throw new RuntimeException(ioEx);
832                 } finally {
833                     try {
834                         // Since the raw FD is created by init and then loaded from an environment
835                         // variable (as opposed to being created by the LocalSocketImpl itself),
836                         // the LocalSocket/LocalSocketImpl does not own the Os-level socket. See
837                         // the spec for LocalSocket.createConnectedLocalSocket(FileDescriptor fd).
838                         // Thus closing the LocalSocket does not suffice. See b/130309968 for more
839                         // discussion.
840                         FileDescriptor fd = usapPoolSocket.getFileDescriptor();
841                         usapPoolSocket.close();
842                         Os.close(fd);
843                     } catch (ErrnoException | IOException ex) {
844                         Log.e("USAP", "Failed to close USAP pool socket");
845                         throw new RuntimeException(ex);
846                     }
847                 }
848             }
849 
850             if (writePipe != null) {
851                 try {
852                     ByteArrayOutputStream buffer =
853                             new ByteArrayOutputStream(Zygote.USAP_MANAGEMENT_MESSAGE_BYTES);
854                     DataOutputStream outputStream = new DataOutputStream(buffer);
855 
856                     // This is written as a long so that the USAP reporting pipe and USAP pool
857                     // event FD handlers in ZygoteServer.runSelectLoop can be unified.  These two
858                     // cases should both send/receive 8 bytes.
859                     // TODO: Needs tweaking to handle the non-Usap invoke-with case, which expects
860                     // a different format.
861                     outputStream.writeLong(pid);
862                     outputStream.flush();
863                     Os.write(writePipe, buffer.toByteArray(), 0, buffer.size());
864                 } catch (Exception ex) {
865                     Log.e("USAP",
866                             String.format("Failed to write PID (%d) to pipe (%d): %s",
867                                     pid, writePipe.getInt$(), ex.getMessage()));
868                     throw new RuntimeException(ex);
869                 } finally {
870                     IoUtils.closeQuietly(writePipe);
871                 }
872             }
873 
874             specializeAppProcess(args.mUid, args.mGid, args.mGids,
875                                  args.mRuntimeFlags, rlimits, args.mMountExternal,
876                                  args.mSeInfo, args.mNiceName, args.mStartChildZygote,
877                                  args.mInstructionSet, args.mAppDataDir, args.mIsTopApp,
878                                  args.mPkgDataInfoList, args.mAllowlistedDataInfoList,
879                                  args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs,
880                                  args.mBindMountSyspropOverrides);
881 
882             // While `specializeAppProcess` sets the thread name on the process's main thread, this
883             // is distinct from the app process name which appears in stack traces, as the latter is
884             // sourced from the argument buffer of the Process class. Set the app process name here.
885             Zygote.setAppProcessName(args, TAG);
886 
887             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
888 
889             return ZygoteInit.zygoteInit(args.mTargetSdkVersion,
890                                          args.mDisabledCompatChanges,
891                                          args.mRemainingArgs,
892                                          null /* classLoader */);
893         } finally {
894             // Unblock SIGTERM to restore the process to default behavior.
895             unblockSigTerm();
896         }
897     }
898 
blockSigTerm()899     private static void blockSigTerm() {
900         nativeBlockSigTerm();
901     }
902 
nativeBlockSigTerm()903     private static native void nativeBlockSigTerm();
904 
unblockSigTerm()905     private static void unblockSigTerm() {
906         nativeUnblockSigTerm();
907     }
908 
nativeUnblockSigTerm()909     private static native void nativeUnblockSigTerm();
910 
boostUsapPriority()911     private static void boostUsapPriority() {
912         nativeBoostUsapPriority();
913     }
914 
nativeBoostUsapPriority()915     private static native void nativeBoostUsapPriority();
916 
setAppProcessName(ZygoteArguments args, String loggingTag)917     static void setAppProcessName(ZygoteArguments args, String loggingTag) {
918         if (args.mNiceName != null) {
919             Process.setArgV0(args.mNiceName);
920         } else if (args.mPackageName != null) {
921             Process.setArgV0(args.mPackageName);
922         } else {
923             Log.w(loggingTag, "Unable to set package name.");
924         }
925     }
926 
927     private static final String USAP_ERROR_PREFIX = "Invalid command to USAP: ";
928 
929     /**
930      * Checks a set of zygote arguments to see if they can be handled by a USAP.  Throws an
931      * exception if an invalid arugment is encountered.
932      * @param args  The arguments to test
933      */
validateUsapCommand(ZygoteArguments args)934     private static void validateUsapCommand(ZygoteArguments args) {
935         if (args.mAbiListQuery) {
936             throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--query-abi-list");
937         } else if (args.mPidQuery) {
938             throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--get-pid");
939         } else if (args.mPreloadDefault) {
940             throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--preload-default");
941         } else if (args.mPreloadPackage != null) {
942             throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--preload-package");
943         } else if (args.mPreloadApp != null) {
944             throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--preload-app");
945         } else if (args.mStartChildZygote) {
946             throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--start-child-zygote");
947         } else if (args.mApiDenylistExemptions != null) {
948             throw new IllegalArgumentException(
949                     USAP_ERROR_PREFIX + "--set-api-denylist-exemptions");
950         } else if (args.mHiddenApiAccessLogSampleRate != -1) {
951             throw new IllegalArgumentException(
952                     USAP_ERROR_PREFIX + "--hidden-api-log-sampling-rate=");
953         } else if (args.mHiddenApiAccessStatslogSampleRate != -1) {
954             throw new IllegalArgumentException(
955                     USAP_ERROR_PREFIX + "--hidden-api-statslog-sampling-rate=");
956         } else if (args.mInvokeWith != null) {
957             throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--invoke-with");
958         } else if (args.mPermittedCapabilities != 0 || args.mEffectiveCapabilities != 0) {
959             throw new ZygoteSecurityException("Client may not specify capabilities: "
960                 + "permitted=0x" + Long.toHexString(args.mPermittedCapabilities)
961                 + ", effective=0x" + Long.toHexString(args.mEffectiveCapabilities));
962         }
963     }
964 
965     /**
966      * @return  Raw file descriptors for the read-end of USAP reporting pipes.
967      */
getUsapPipeFDs()968     static int[] getUsapPipeFDs() {
969         return nativeGetUsapPipeFDs();
970     }
971 
nativeGetUsapPipeFDs()972     private static native int[] nativeGetUsapPipeFDs();
973 
974     /**
975      * Remove the USAP table entry for the provided process ID.
976      *
977      * @param usapPID  Process ID of the entry to remove
978      * @return True if the entry was removed; false if it doesn't exist
979      */
removeUsapTableEntry(int usapPID)980     static boolean removeUsapTableEntry(int usapPID) {
981         return nativeRemoveUsapTableEntry(usapPID);
982     }
983 
984     @CriticalNative
nativeRemoveUsapTableEntry(int usapPID)985     private static native boolean nativeRemoveUsapTableEntry(int usapPID);
986 
987     /**
988      * Return the minimum child uid that the given peer is allowed to create.
989      * uid 1000 (Process.SYSTEM_UID) may specify any uid &ge; 1000 in normal
990      * operation. It may also specify any gid and setgroups() list it chooses.
991      * In factory test mode, it may specify any UID.
992      */
minChildUid(Credentials peer)993     static int minChildUid(Credentials peer) {
994         if (peer.getUid() == Process.SYSTEM_UID
995                 && FactoryTest.getMode() == FactoryTest.FACTORY_TEST_OFF) {
996             /* In normal operation, SYSTEM_UID can only specify a restricted
997              * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
998              */
999             return Process.SYSTEM_UID;
1000         } else {
1001             return 0;
1002         }
1003     }
1004 
1005     /*
1006      * Adjust uid and gid arguments, ensuring that the security policy is satisfied.
1007      * @param args non-null; zygote spawner arguments
1008      * @param peer non-null; peer credentials
1009      * @throws ZygoteSecurityException Indicates a security issue when applying the UID based
1010      *  security policies
1011      */
applyUidSecurityPolicy(ZygoteArguments args, Credentials peer)1012     static void applyUidSecurityPolicy(ZygoteArguments args, Credentials peer)
1013             throws ZygoteSecurityException {
1014 
1015         if (args.mUidSpecified && (args.mUid < minChildUid(peer))) {
1016             throw new ZygoteSecurityException(
1017                     "System UID may not launch process with UID < "
1018                     + Process.SYSTEM_UID);
1019         }
1020 
1021         // If not otherwise specified, uid and gid are inherited from peer
1022         if (!args.mUidSpecified) {
1023             args.mUid = peer.getUid();
1024             args.mUidSpecified = true;
1025         }
1026         if (!args.mGidSpecified) {
1027             args.mGid = peer.getGid();
1028             args.mGidSpecified = true;
1029         }
1030     }
1031 
1032     /**
1033      * This will enable jdwp by default for all apps. It is OK to cache this property
1034      * because we expect to reboot the system whenever this property changes
1035      */
1036     private static final boolean ENABLE_JDWP = SystemProperties.get(
1037                           "persist.debug.dalvik.vm.jdwp.enabled").equals("1");
1038 
1039     /**
1040      * This will enable ptrace by default for all apps. It is OK to cache this property
1041      * because we expect to reboot the system whenever this property changes
1042      */
1043     private static final boolean ENABLE_PTRACE = SystemProperties.get(
1044                           "persist.debug.ptrace.enabled").equals("1");
1045 
1046     /**
1047      * Applies debugger system properties to the zygote arguments.
1048      *
1049      * For eng builds all apps are debuggable with JDWP and ptrace.
1050      *
1051      * On userdebug builds if persist.debug.dalvik.vm.jdwp.enabled
1052      * is 1 all apps are debuggable with JDWP and ptrace. Otherwise, the
1053      * debugger state is specified via the "--enable-jdwp" flag in the
1054      * spawn request.
1055      *
1056      * On userdebug builds if persist.debug.ptrace.enabled is 1 all
1057      * apps are debuggable with ptrace.
1058      *
1059      * @param args non-null; zygote spawner args
1060      */
applyDebuggerSystemProperty(ZygoteArguments args)1061     static void applyDebuggerSystemProperty(ZygoteArguments args) {
1062         if (Build.IS_ENG || (Build.IS_USERDEBUG && ENABLE_JDWP)) {
1063             args.mRuntimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
1064             // Also enable ptrace when JDWP is enabled for consistency with
1065             // before persist.debug.ptrace.enabled existed.
1066             args.mRuntimeFlags |= Zygote.DEBUG_ENABLE_PTRACE;
1067         }
1068         if (Build.IS_ENG || (Build.IS_USERDEBUG && ENABLE_PTRACE)) {
1069             args.mRuntimeFlags |= Zygote.DEBUG_ENABLE_PTRACE;
1070         }
1071     }
1072 
1073     /**
1074      * Applies zygote security policy.
1075      * Based on the credentials of the process issuing a zygote command:
1076      * <ol>
1077      * <li> uid 0 (root) may specify --invoke-with to launch Zygote with a
1078      * wrapper command.
1079      * <li> Any other uid may not specify any invoke-with argument.
1080      * </ul>
1081      *
1082      * @param args non-null; zygote spawner arguments
1083      * @param peer non-null; peer credentials
1084      * @throws ZygoteSecurityException Thrown when `--invoke-with` is specified for a non-debuggable
1085      *  application.
1086      */
applyInvokeWithSecurityPolicy(ZygoteArguments args, Credentials peer)1087     static void applyInvokeWithSecurityPolicy(ZygoteArguments args, Credentials peer)
1088             throws ZygoteSecurityException {
1089         int peerUid = peer.getUid();
1090 
1091         if (args.mInvokeWith != null && peerUid != 0
1092                 && (args.mRuntimeFlags
1093                     & (Zygote.DEBUG_ENABLE_JDWP | Zygote.DEBUG_ENABLE_PTRACE)) == 0) {
1094             throw new ZygoteSecurityException("Peer is permitted to specify an "
1095                 + "explicit invoke-with wrapper command only for debuggable "
1096                 + "applications.");
1097         }
1098     }
1099 
1100     /**
1101      * Gets the wrap property if set.
1102      *
1103      * @param appName the application name to check
1104      * @return value of wrap property or null if property not set or
1105      * null if app_name is null or null if app_name is empty
1106      */
getWrapProperty(String appName)1107     public static String getWrapProperty(String appName) {
1108         if (appName == null || appName.isEmpty()) {
1109             return null;
1110         }
1111 
1112         String propertyValue = SystemProperties.get("wrap." + appName);
1113         if (propertyValue != null && !propertyValue.isEmpty()) {
1114             return propertyValue;
1115         }
1116         return null;
1117     }
1118 
1119     /**
1120      * Applies invoke-with system properties to the zygote arguments.
1121      *
1122      * @param args non-null; zygote args
1123      */
applyInvokeWithSystemProperty(ZygoteArguments args)1124     static void applyInvokeWithSystemProperty(ZygoteArguments args) {
1125         if (args.mInvokeWith == null) {
1126             args.mInvokeWith = getWrapProperty(args.mNiceName);
1127         }
1128     }
1129 
1130     /**
1131      * Creates a managed LocalServerSocket object using a file descriptor
1132      * created by an init.rc script.  The init scripts that specify the
1133      * sockets name can be found in system/core/rootdir.  The socket is bound
1134      * to the file system in the /dev/sockets/ directory, and the file
1135      * descriptor is shared via the ANDROID_SOCKET_<socketName> environment
1136      * variable.
1137      */
createManagedSocketFromInitSocket(String socketName)1138     static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
1139         int fileDesc;
1140         final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
1141 
1142         try {
1143             String env = System.getenv(fullSocketName);
1144             fileDesc = Integer.parseInt(env);
1145         } catch (RuntimeException ex) {
1146             throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);
1147         }
1148 
1149         try {
1150             FileDescriptor fd = new FileDescriptor();
1151             fd.setInt$(fileDesc);
1152             return new LocalServerSocket(fd);
1153         } catch (IOException ex) {
1154             throw new RuntimeException(
1155                 "Error building socket from file descriptor: " + fileDesc, ex);
1156         }
1157     }
1158 
1159     // This function is called from native code in com_android_internal_os_Zygote.cpp
1160     @SuppressWarnings("unused")
callPostForkSystemServerHooks(int runtimeFlags)1161     private static void callPostForkSystemServerHooks(int runtimeFlags) {
1162         // SystemServer specific post fork hooks run before child post fork hooks.
1163         ZygoteHooks.postForkSystemServer(runtimeFlags);
1164     }
1165 
1166     // This function is called from native code in com_android_internal_os_Zygote.cpp
1167     @SuppressWarnings("unused")
callPostForkChildHooks(int runtimeFlags, boolean isSystemServer, boolean isZygote, String instructionSet)1168     private static void callPostForkChildHooks(int runtimeFlags, boolean isSystemServer,
1169             boolean isZygote, String instructionSet) {
1170         ZygoteHooks.postForkChild(runtimeFlags, isSystemServer, isZygote, instructionSet);
1171     }
1172 
1173     /**
1174      * Executes "/system/bin/sh -c &lt;command&gt;" using the exec() system call.
1175      * This method throws a runtime exception if exec() failed, otherwise, this
1176      * method never returns.
1177      *
1178      * @param command The shell command to execute.
1179      */
execShell(String command)1180     static void execShell(String command) {
1181         String[] args = { "/system/bin/sh", "-c", command };
1182         try {
1183             Os.execv(args[0], args);
1184         } catch (ErrnoException e) {
1185             throw new RuntimeException(e);
1186         }
1187     }
1188 
1189     /**
1190      * Appends quotes shell arguments to the specified string builder.
1191      * The arguments are quoted using single-quotes, escaped if necessary,
1192      * prefixed with a space, and appended to the command.
1193      *
1194      * @param command A string builder for the shell command being constructed.
1195      * @param args An array of argument strings to be quoted and appended to the command.
1196      * @see #execShell(String)
1197      */
appendQuotedShellArgs(StringBuilder command, String[] args)1198     static void appendQuotedShellArgs(StringBuilder command, String[] args) {
1199         for (String arg : args) {
1200             command.append(" '").append(arg.replace("'", "'\\''")).append("'");
1201         }
1202     }
1203 
1204     /**
1205      * Parse the given unsolicited zygote message as type SIGCHLD,
1206      * extract the payload information into the given output buffer.
1207      *
1208      * @param in The unsolicited zygote message to be parsed
1209      * @param length The number of bytes in the message
1210      * @param out The output buffer where the payload information will be placed
1211      * @return Number of elements being place into output buffer, or -1 if
1212      *         either the message is malformed or not the type as expected here.
1213      *
1214      * @hide
1215      */
1216     @FastNative
nativeParseSigChld(byte[] in, int length, int[] out)1217     public static native int nativeParseSigChld(byte[] in, int length, int[] out);
1218 
1219     /**
1220      * Returns whether the hardware supports memory tagging (ARM MTE).
1221      */
nativeSupportsMemoryTagging()1222     public static native boolean nativeSupportsMemoryTagging();
1223 
1224     /**
1225      * Returns whether the kernel supports tagged pointers. Present in the
1226      * Android Common Kernel from 4.14 and up. By default, you should prefer
1227      * fully-feature Memory Tagging, rather than the static Tagged Pointers.
1228      */
nativeSupportsTaggedPointers()1229     public static native boolean nativeSupportsTaggedPointers();
1230 
1231     /**
1232      * Returns the current native tagging level, as one of the
1233      * MEMORY_TAG_LEVEL_* constants. Returns zero if no tagging is present, or
1234      * we failed to determine the level.
1235      */
nativeCurrentTaggingLevel()1236     public static native int nativeCurrentTaggingLevel();
1237 
1238     /**
1239      * Native heap allocations will now have a non-zero tag in the most significant byte.
1240      *
1241      * @see <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged
1242      *     Pointers</a>
1243      */
1244     @ChangeId
1245     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
1246     private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
1247 
1248     /**
1249      * Native heap allocations in AppZygote process and its descendants will now have a non-zero tag
1250      * in the most significant byte.
1251      *
1252      * @see <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged
1253      *     Pointers</a>
1254      */
1255     @ChangeId
1256     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
1257     private static final long NATIVE_HEAP_POINTER_TAGGING_SECONDARY_ZYGOTE = 207557677;
1258 
1259     /**
1260      * Enable asynchronous (ASYNC) memory tag checking in this process. This flag will only have an
1261      * effect on hardware supporting the ARM Memory Tagging Extension (MTE).
1262      */
1263     @ChangeId @Disabled
1264     private static final long NATIVE_MEMTAG_ASYNC = 135772972; // This is a bug id.
1265 
1266     /**
1267      * Enable synchronous (SYNC) memory tag checking in this process. This flag will only have an
1268      * effect on hardware supporting the ARM Memory Tagging Extension (MTE). If both
1269      * NATIVE_MEMTAG_ASYNC and this option is selected, this option takes preference and MTE is
1270      * enabled in SYNC mode.
1271      */
1272     @ChangeId @Disabled
1273     private static final long NATIVE_MEMTAG_SYNC = 177438394; // This is a bug id.
1274 
1275     /** Enable automatic zero-initialization of native heap memory allocations. */
1276     @ChangeId @Disabled
1277     private static final long NATIVE_HEAP_ZERO_INIT = 178038272; // This is a bug id.
1278 
1279     /**
1280      * Enable sampled memory bug detection in the app.
1281      *
1282      * @see <a href="https://source.android.com/devices/tech/debug/gwp-asan">GWP-ASan</a>.
1283      */
1284     @ChangeId @Disabled private static final long GWP_ASAN = 135634846; // This is a bug id.
1285 
memtagModeToZygoteMemtagLevel(int memtagMode)1286     private static int memtagModeToZygoteMemtagLevel(int memtagMode) {
1287         switch (memtagMode) {
1288             case ApplicationInfo.MEMTAG_ASYNC:
1289                 return MEMORY_TAG_LEVEL_ASYNC;
1290             case ApplicationInfo.MEMTAG_SYNC:
1291                 return MEMORY_TAG_LEVEL_SYNC;
1292             default:
1293                 return MEMORY_TAG_LEVEL_NONE;
1294         }
1295     }
1296 
isCompatChangeEnabled( long change, @NonNull ApplicationInfo info, @Nullable IPlatformCompat platformCompat, int enabledAfter)1297     private static boolean isCompatChangeEnabled(
1298             long change,
1299             @NonNull ApplicationInfo info,
1300             @Nullable IPlatformCompat platformCompat,
1301             int enabledAfter) {
1302         try {
1303             if (platformCompat != null) return platformCompat.isChangeEnabled(change, info);
1304         } catch (RemoteException ignore) {
1305         }
1306         return enabledAfter > 0 && info.targetSdkVersion > enabledAfter;
1307     }
1308 
1309     // Returns the requested memory tagging level.
getRequestedMemtagLevel( @onNull ApplicationInfo info, @Nullable ProcessInfo processInfo, @Nullable IPlatformCompat platformCompat)1310     private static int getRequestedMemtagLevel(
1311             @NonNull ApplicationInfo info,
1312             @Nullable ProcessInfo processInfo,
1313             @Nullable IPlatformCompat platformCompat) {
1314         String appOverride = SystemProperties.get("persist.arm64.memtag.app." + info.packageName);
1315         if ("sync".equals(appOverride)) {
1316             return MEMORY_TAG_LEVEL_SYNC;
1317         } else if ("async".equals(appOverride)) {
1318             return MEMORY_TAG_LEVEL_ASYNC;
1319         } else if ("off".equals(appOverride)) {
1320             return MEMORY_TAG_LEVEL_NONE;
1321         }
1322 
1323         // Look at the process attribute first.
1324         if (processInfo != null && processInfo.memtagMode != ApplicationInfo.MEMTAG_DEFAULT) {
1325             return memtagModeToZygoteMemtagLevel(processInfo.memtagMode);
1326         }
1327 
1328         // Then at the application attribute.
1329         if (info.getMemtagMode() != ApplicationInfo.MEMTAG_DEFAULT) {
1330             return memtagModeToZygoteMemtagLevel(info.getMemtagMode());
1331         }
1332 
1333         if (isCompatChangeEnabled(NATIVE_MEMTAG_SYNC, info, platformCompat, 0)) {
1334             return MEMORY_TAG_LEVEL_SYNC;
1335         }
1336 
1337         if (isCompatChangeEnabled(NATIVE_MEMTAG_ASYNC, info, platformCompat, 0)) {
1338             return MEMORY_TAG_LEVEL_ASYNC;
1339         }
1340 
1341         // Check to ensure the app hasn't explicitly opted-out of TBI via. the manifest attribute.
1342         if (!info.allowsNativeHeapPointerTagging()) {
1343             return MEMORY_TAG_LEVEL_NONE;
1344         }
1345 
1346         String defaultLevel = SystemProperties.get("persist.arm64.memtag.app_default");
1347         if ("sync".equals(defaultLevel)) {
1348             return MEMORY_TAG_LEVEL_SYNC;
1349         } else if ("async".equals(defaultLevel)) {
1350             return MEMORY_TAG_LEVEL_ASYNC;
1351         }
1352 
1353         // Check to see that the compat feature for TBI is enabled.
1354         if (isCompatChangeEnabled(
1355                 NATIVE_HEAP_POINTER_TAGGING, info, platformCompat, Build.VERSION_CODES.Q)) {
1356             return MEMORY_TAG_LEVEL_TBI;
1357         }
1358 
1359         return MEMORY_TAG_LEVEL_NONE;
1360     }
1361 
decideTaggingLevel( @onNull ApplicationInfo info, @Nullable ProcessInfo processInfo, @Nullable IPlatformCompat platformCompat)1362     private static int decideTaggingLevel(
1363             @NonNull ApplicationInfo info,
1364             @Nullable ProcessInfo processInfo,
1365             @Nullable IPlatformCompat platformCompat) {
1366         // Get the desired tagging level (app manifest + compat features).
1367         int level = getRequestedMemtagLevel(info, processInfo, platformCompat);
1368 
1369         // Take into account the hardware capabilities.
1370         if (nativeSupportsMemoryTagging()) {
1371             // MTE devices can not do TBI, because the Zygote process already has live MTE
1372             // allocations. Downgrade TBI to NONE.
1373             if (level == MEMORY_TAG_LEVEL_TBI) {
1374                 level = MEMORY_TAG_LEVEL_NONE;
1375             }
1376         } else if (nativeSupportsTaggedPointers()) {
1377             // TBI-but-not-MTE devices downgrade MTE modes to TBI.
1378             // The idea is that if an app opts into full hardware tagging (MTE), it must be ok with
1379             // the "fake" pointer tagging (TBI).
1380             if (level == MEMORY_TAG_LEVEL_ASYNC || level == MEMORY_TAG_LEVEL_SYNC) {
1381                 level = MEMORY_TAG_LEVEL_TBI;
1382             }
1383         } else {
1384             // Otherwise disable all tagging.
1385             level = MEMORY_TAG_LEVEL_NONE;
1386         }
1387 
1388         // If we requested "sync" mode for the whole platform, upgrade mode for apps that enable
1389         // MTE.
1390         // This makes debugging a lot easier.
1391         if (level == MEMORY_TAG_LEVEL_ASYNC
1392                 && (Build.IS_USERDEBUG || Build.IS_ENG)
1393                 && "sync".equals(SystemProperties.get("persist.arm64.memtag.default"))) {
1394             level = MEMORY_TAG_LEVEL_SYNC;
1395         }
1396 
1397         return level;
1398     }
1399 
decideGwpAsanLevel( @onNull ApplicationInfo info, @Nullable ProcessInfo processInfo, @Nullable IPlatformCompat platformCompat)1400     private static int decideGwpAsanLevel(
1401             @NonNull ApplicationInfo info,
1402             @Nullable ProcessInfo processInfo,
1403             @Nullable IPlatformCompat platformCompat) {
1404         // Look at the process attribute first.
1405         if (processInfo != null && processInfo.gwpAsanMode != ApplicationInfo.GWP_ASAN_DEFAULT) {
1406             return processInfo.gwpAsanMode == ApplicationInfo.GWP_ASAN_ALWAYS
1407                     ? GWP_ASAN_LEVEL_ALWAYS
1408                     : GWP_ASAN_LEVEL_NEVER;
1409         }
1410         // Then at the application attribute.
1411         if (info.getGwpAsanMode() != ApplicationInfo.GWP_ASAN_DEFAULT) {
1412             return info.getGwpAsanMode() == ApplicationInfo.GWP_ASAN_ALWAYS
1413                     ? GWP_ASAN_LEVEL_ALWAYS
1414                     : GWP_ASAN_LEVEL_NEVER;
1415         }
1416         if (isCompatChangeEnabled(GWP_ASAN, info, platformCompat, 0)) {
1417             return GWP_ASAN_LEVEL_ALWAYS;
1418         }
1419         if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1420             return GWP_ASAN_LEVEL_LOTTERY;
1421         }
1422         return GWP_ASAN_LEVEL_DEFAULT;
1423     }
1424 
enableNativeHeapZeroInit( @onNull ApplicationInfo info, @Nullable ProcessInfo processInfo, @Nullable IPlatformCompat platformCompat)1425     private static boolean enableNativeHeapZeroInit(
1426             @NonNull ApplicationInfo info,
1427             @Nullable ProcessInfo processInfo,
1428             @Nullable IPlatformCompat platformCompat) {
1429         // Look at the process attribute first.
1430         if (processInfo != null
1431                 && processInfo.nativeHeapZeroInitialized != ApplicationInfo.ZEROINIT_DEFAULT) {
1432             return processInfo.nativeHeapZeroInitialized == ApplicationInfo.ZEROINIT_ENABLED;
1433         }
1434         // Then at the application attribute.
1435         if (info.getNativeHeapZeroInitialized() != ApplicationInfo.ZEROINIT_DEFAULT) {
1436             return info.getNativeHeapZeroInitialized() == ApplicationInfo.ZEROINIT_ENABLED;
1437         }
1438         // Compat feature last.
1439         if (isCompatChangeEnabled(NATIVE_HEAP_ZERO_INIT, info, platformCompat, 0)) {
1440             return true;
1441         }
1442         return false;
1443     }
1444 
1445     /**
1446      * Returns Zygote runtimeFlags for memory safety features (MTE, GWP-ASan, nativeHeadZeroInit)
1447      * for a given app.
1448      */
getMemorySafetyRuntimeFlags( @onNull ApplicationInfo info, @Nullable ProcessInfo processInfo, @Nullable String instructionSet, @Nullable IPlatformCompat platformCompat)1449     public static int getMemorySafetyRuntimeFlags(
1450             @NonNull ApplicationInfo info,
1451             @Nullable ProcessInfo processInfo,
1452             @Nullable String instructionSet,
1453             @Nullable IPlatformCompat platformCompat) {
1454         int runtimeFlags = decideGwpAsanLevel(info, processInfo, platformCompat);
1455         // If instructionSet is non-null, this indicates that the system_server is spawning a
1456         // process with an ISA that may be different from its own. System (kernel and hardware)
1457         // compatibility for these features is checked in the decideTaggingLevel in the
1458         // system_server process (not the child process). As both MTE and TBI are only supported
1459         // in aarch64, we can simply ensure that the new process is also aarch64. This prevents
1460         // the mismatch where a 64-bit system server spawns a 32-bit child that thinks it should
1461         // enable some tagging variant. Theoretically, a 32-bit system server could exist that
1462         // spawns 64-bit processes, in which case the new process won't get any tagging. This is
1463         // fine as we haven't seen this configuration in practice, and we can reasonable assume
1464         // that if tagging is desired, the system server will be 64-bit.
1465         if (instructionSet == null || instructionSet.equals("arm64")) {
1466             runtimeFlags |= decideTaggingLevel(info, processInfo, platformCompat);
1467         }
1468         if (enableNativeHeapZeroInit(info, processInfo, platformCompat)) {
1469             runtimeFlags |= NATIVE_HEAP_ZERO_INIT_ENABLED;
1470         }
1471         return runtimeFlags;
1472     }
1473 
1474     /**
1475      * Returns Zygote runtimeFlags for memory safety features (MTE, GWP-ASan, nativeHeadZeroInit)
1476      * for a secondary zygote (AppZygote or WebViewZygote).
1477      */
getMemorySafetyRuntimeFlagsForSecondaryZygote( @onNull ApplicationInfo info, @Nullable ProcessInfo processInfo)1478     public static int getMemorySafetyRuntimeFlagsForSecondaryZygote(
1479             @NonNull ApplicationInfo info, @Nullable ProcessInfo processInfo) {
1480         final IPlatformCompat platformCompat =
1481                 IPlatformCompat.Stub.asInterface(
1482                         ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
1483         int runtimeFlags =
1484                 getMemorySafetyRuntimeFlags(
1485                         info, processInfo, null /*instructionSet*/, platformCompat);
1486 
1487         // TBI ("fake" pointer tagging) in AppZygote is controlled by a separate compat feature.
1488         if ((runtimeFlags & MEMORY_TAG_LEVEL_MASK) == MEMORY_TAG_LEVEL_TBI
1489                 && isCompatChangeEnabled(
1490                         NATIVE_HEAP_POINTER_TAGGING_SECONDARY_ZYGOTE,
1491                         info,
1492                         platformCompat,
1493                         Build.VERSION_CODES.S)) {
1494             // Reset memory tag level to NONE.
1495             runtimeFlags &= ~MEMORY_TAG_LEVEL_MASK;
1496             runtimeFlags |= MEMORY_TAG_LEVEL_NONE;
1497         }
1498         return runtimeFlags;
1499     }
1500 }
1501