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