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 ≥ 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 <command>" 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