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