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