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