diff --git a/core/java/android/os/AppZygote.java b/core/java/android/os/AppZygote.java index c8b4226ecae0f..07fbe4a04ff18 100644 --- a/core/java/android/os/AppZygote.java +++ b/core/java/android/os/AppZygote.java @@ -17,9 +17,11 @@ package android.os; import android.content.pm.ApplicationInfo; +import android.content.pm.ProcessInfo; import android.util.Log; import com.android.internal.annotations.GuardedBy; +import com.android.internal.os.Zygote; import dalvik.system.VMRuntime; @@ -45,8 +47,6 @@ public class AppZygote { // Last UID/GID of the range the AppZygote can setuid()/setgid() to private final int mZygoteUidGidMax; - private final int mZygoteRuntimeFlags; - private final Object mLock = new Object(); /** @@ -57,14 +57,15 @@ public class AppZygote { private ChildZygoteProcess mZygote; private final ApplicationInfo mAppInfo; + private final ProcessInfo mProcessInfo; - public AppZygote(ApplicationInfo appInfo, int zygoteUid, int uidGidMin, int uidGidMax, - int runtimeFlags) { + public AppZygote(ApplicationInfo appInfo, ProcessInfo processInfo, int zygoteUid, int uidGidMin, + int uidGidMax) { mAppInfo = appInfo; + mProcessInfo = processInfo; mZygoteUid = zygoteUid; mZygoteUidGidMin = uidGidMin; mZygoteUidGidMax = uidGidMax; - mZygoteRuntimeFlags = runtimeFlags; } /** @@ -108,13 +109,15 @@ public class AppZygote { String abi = mAppInfo.primaryCpuAbi != null ? mAppInfo.primaryCpuAbi : Build.SUPPORTED_ABIS[0]; try { + int runtimeFlags = Zygote.getMemorySafetyRuntimeFlagsForSecondaryZygote( + mAppInfo, mProcessInfo); mZygote = Process.ZYGOTE_PROCESS.startChildZygote( "com.android.internal.os.AppZygoteInit", mAppInfo.processName + "_zygote", mZygoteUid, mZygoteUid, null, // gids - mZygoteRuntimeFlags, // runtimeFlags + runtimeFlags, "app_zygote", // seInfo abi, // abi abi, // acceptedAbiList diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java index 2bfbe4bdfba75..bc7a5fda6f7af 100644 --- a/core/java/android/webkit/WebViewZygote.java +++ b/core/java/android/webkit/WebViewZygote.java @@ -25,6 +25,7 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.GuardedBy; +import com.android.internal.os.Zygote; /** @hide */ public class WebViewZygote { @@ -127,13 +128,15 @@ public class WebViewZygote { try { String abi = sPackage.applicationInfo.primaryCpuAbi; + int runtimeFlags = Zygote.getMemorySafetyRuntimeFlagsForSecondaryZygote( + sPackage.applicationInfo, null); sZygote = Process.ZYGOTE_PROCESS.startChildZygote( "com.android.internal.os.WebViewZygoteInit", "webview_zygote", Process.WEBVIEW_ZYGOTE_UID, Process.WEBVIEW_ZYGOTE_UID, null, // gids - 0, // runtimeFlags + runtimeFlags, "webview_zygote", // seInfo abi, // abi TextUtils.join(",", Build.SUPPORTED_ABIS), diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 6d4b8c5ea1adc..b1e7d15cbf4a9 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -20,13 +20,21 @@ import static android.system.OsConstants.O_CLOEXEC; import android.annotation.NonNull; import android.annotation.Nullable; +import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; +import android.compat.annotation.EnabledAfter; +import android.content.Context; import android.content.pm.ApplicationInfo; +import android.content.pm.ProcessInfo; import android.net.Credentials; import android.net.LocalServerSocket; import android.net.LocalSocket; +import android.os.Build; import android.os.FactoryTest; import android.os.IVold; import android.os.Process; +import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemProperties; import android.os.Trace; import android.provider.DeviceConfig; @@ -34,6 +42,7 @@ import android.system.ErrnoException; import android.system.Os; import android.util.Log; +import com.android.internal.compat.IPlatformCompat; import com.android.internal.net.NetworkUtilsInternal; import dalvik.annotation.optimization.CriticalNative; @@ -125,6 +134,7 @@ public final class Zygote { public static final int MEMORY_TAG_LEVEL_MASK = (1 << 19) | (1 << 20); public static final int MEMORY_TAG_LEVEL_NONE = 0; + /** * Enable pointer tagging in this process. * Tags are checked during memory deallocation, but not on access. @@ -170,10 +180,8 @@ public final class Zygote { */ public static final int GWP_ASAN_LEVEL_ALWAYS = 1 << 22; - /** - * Enable automatic zero-initialization of native heap memory allocations. - */ - public static final int NATIVE_HEAP_ZERO_INIT = 1 << 23; + /** Enable automatic zero-initialization of native heap memory allocations. */ + public static final int NATIVE_HEAP_ZERO_INIT_ENABLED = 1 << 23; /** * Enable profiling from system services. This loads profiling related plugins in ART. @@ -1170,4 +1178,251 @@ public final class Zygote { * we failed to determine the level. */ public static native int nativeCurrentTaggingLevel(); + + /** + * Native heap allocations will now have a non-zero tag in the most significant byte. + * + * @see Tagged + * Pointers + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) + private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id. + + /** + * Native heap allocations in AppZygote process and its descendants will now have a non-zero tag + * in the most significant byte. + * + * @see Tagged + * Pointers + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S) + private static final long NATIVE_HEAP_POINTER_TAGGING_SECONDARY_ZYGOTE = 207557677; + + /** + * Enable asynchronous (ASYNC) memory tag checking in this process. This flag will only have an + * effect on hardware supporting the ARM Memory Tagging Extension (MTE). + */ + @ChangeId @Disabled + private static final long NATIVE_MEMTAG_ASYNC = 135772972; // This is a bug id. + + /** + * Enable synchronous (SYNC) memory tag checking in this process. This flag will only have an + * effect on hardware supporting the ARM Memory Tagging Extension (MTE). If both + * NATIVE_MEMTAG_ASYNC and this option is selected, this option takes preference and MTE is + * enabled in SYNC mode. + */ + @ChangeId @Disabled + private static final long NATIVE_MEMTAG_SYNC = 177438394; // This is a bug id. + + /** Enable automatic zero-initialization of native heap memory allocations. */ + @ChangeId @Disabled + private static final long NATIVE_HEAP_ZERO_INIT = 178038272; // This is a bug id. + + /** + * Enable sampled memory bug detection in the app. + * + * @see GWP-ASan. + */ + @ChangeId @Disabled private static final long GWP_ASAN = 135634846; // This is a bug id. + + private static int memtagModeToZygoteMemtagLevel(int memtagMode) { + switch (memtagMode) { + case ApplicationInfo.MEMTAG_ASYNC: + return MEMORY_TAG_LEVEL_ASYNC; + case ApplicationInfo.MEMTAG_SYNC: + return MEMORY_TAG_LEVEL_SYNC; + default: + return MEMORY_TAG_LEVEL_NONE; + } + } + + private static boolean isCompatChangeEnabled( + long change, + @NonNull ApplicationInfo info, + @Nullable IPlatformCompat platformCompat, + int enabledAfter) { + try { + if (platformCompat != null) return platformCompat.isChangeEnabled(change, info); + } catch (RemoteException ignore) { + } + return enabledAfter > 0 && info.targetSdkVersion > enabledAfter; + } + + // Returns the requested memory tagging level. + private static int getRequestedMemtagLevel( + @NonNull ApplicationInfo info, + @Nullable ProcessInfo processInfo, + @Nullable IPlatformCompat platformCompat) { + // Look at the process attribute first. + if (processInfo != null && processInfo.memtagMode != ApplicationInfo.MEMTAG_DEFAULT) { + return memtagModeToZygoteMemtagLevel(processInfo.memtagMode); + } + + // Then at the application attribute. + if (info.getMemtagMode() != ApplicationInfo.MEMTAG_DEFAULT) { + return memtagModeToZygoteMemtagLevel(info.getMemtagMode()); + } + + if (isCompatChangeEnabled(NATIVE_MEMTAG_SYNC, info, platformCompat, 0)) { + return MEMORY_TAG_LEVEL_SYNC; + } + + if (isCompatChangeEnabled(NATIVE_MEMTAG_ASYNC, info, platformCompat, 0)) { + return MEMORY_TAG_LEVEL_ASYNC; + } + + // Check to ensure the app hasn't explicitly opted-out of TBI via. the manifest attribute. + if (!info.allowsNativeHeapPointerTagging()) { + return MEMORY_TAG_LEVEL_NONE; + } + + String defaultLevel = SystemProperties.get("persist.arm64.memtag.app_default"); + if ("sync".equals(defaultLevel)) { + return MEMORY_TAG_LEVEL_SYNC; + } else if ("async".equals(defaultLevel)) { + return MEMORY_TAG_LEVEL_ASYNC; + } + + // Check to see that the compat feature for TBI is enabled. + if (isCompatChangeEnabled( + NATIVE_HEAP_POINTER_TAGGING, info, platformCompat, Build.VERSION_CODES.Q)) { + return MEMORY_TAG_LEVEL_TBI; + } + + return MEMORY_TAG_LEVEL_NONE; + } + + private static int decideTaggingLevel( + @NonNull ApplicationInfo info, + @Nullable ProcessInfo processInfo, + @Nullable IPlatformCompat platformCompat) { + // Get the desired tagging level (app manifest + compat features). + int level = getRequestedMemtagLevel(info, processInfo, platformCompat); + + // Take into account the hardware capabilities. + if (nativeSupportsMemoryTagging()) { + // MTE devices can not do TBI, because the Zygote process already has live MTE + // allocations. Downgrade TBI to NONE. + if (level == MEMORY_TAG_LEVEL_TBI) { + level = MEMORY_TAG_LEVEL_NONE; + } + } else if (nativeSupportsTaggedPointers()) { + // TBI-but-not-MTE devices downgrade MTE modes to TBI. + // The idea is that if an app opts into full hardware tagging (MTE), it must be ok with + // the "fake" pointer tagging (TBI). + if (level == MEMORY_TAG_LEVEL_ASYNC || level == MEMORY_TAG_LEVEL_SYNC) { + level = MEMORY_TAG_LEVEL_TBI; + } + } else { + // Otherwise disable all tagging. + level = MEMORY_TAG_LEVEL_NONE; + } + + return level; + } + + private static int decideGwpAsanLevel( + @NonNull ApplicationInfo info, + @Nullable ProcessInfo processInfo, + @Nullable IPlatformCompat platformCompat) { + // Look at the process attribute first. + if (processInfo != null && processInfo.gwpAsanMode != ApplicationInfo.GWP_ASAN_DEFAULT) { + return processInfo.gwpAsanMode == ApplicationInfo.GWP_ASAN_ALWAYS + ? GWP_ASAN_LEVEL_ALWAYS + : GWP_ASAN_LEVEL_NEVER; + } + // Then at the application attribute. + if (info.getGwpAsanMode() != ApplicationInfo.GWP_ASAN_DEFAULT) { + return info.getGwpAsanMode() == ApplicationInfo.GWP_ASAN_ALWAYS + ? GWP_ASAN_LEVEL_ALWAYS + : GWP_ASAN_LEVEL_NEVER; + } + // If the app does not specify gwpAsanMode, the default behavior is lottery among the + // system apps, and disabled for user apps, unless overwritten by the compat feature. + if (isCompatChangeEnabled(GWP_ASAN, info, platformCompat, 0)) { + return GWP_ASAN_LEVEL_ALWAYS; + } + if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + return GWP_ASAN_LEVEL_LOTTERY; + } + return GWP_ASAN_LEVEL_NEVER; + } + + private static boolean enableNativeHeapZeroInit( + @NonNull ApplicationInfo info, + @Nullable ProcessInfo processInfo, + @Nullable IPlatformCompat platformCompat) { + // Look at the process attribute first. + if (processInfo != null + && processInfo.nativeHeapZeroInitialized != ApplicationInfo.ZEROINIT_DEFAULT) { + return processInfo.nativeHeapZeroInitialized == ApplicationInfo.ZEROINIT_ENABLED; + } + // Then at the application attribute. + if (info.getNativeHeapZeroInitialized() != ApplicationInfo.ZEROINIT_DEFAULT) { + return info.getNativeHeapZeroInitialized() == ApplicationInfo.ZEROINIT_ENABLED; + } + // Compat feature last. + if (isCompatChangeEnabled(NATIVE_HEAP_ZERO_INIT, info, platformCompat, 0)) { + return true; + } + return false; + } + + /** + * Returns Zygote runtimeFlags for memory safety features (MTE, GWP-ASan, nativeHeadZeroInit) + * for a given app. + */ + public static int getMemorySafetyRuntimeFlags( + @NonNull ApplicationInfo info, + @Nullable ProcessInfo processInfo, + @Nullable String instructionSet, + @Nullable IPlatformCompat platformCompat) { + int runtimeFlags = decideGwpAsanLevel(info, processInfo, platformCompat); + // If instructionSet is non-null, this indicates that the system_server is spawning a + // process with an ISA that may be different from its own. System (kernel and hardware) + // compatibility for these features is checked in the decideTaggingLevel in the + // system_server process (not the child process). As both MTE and TBI are only supported + // in aarch64, we can simply ensure that the new process is also aarch64. This prevents + // the mismatch where a 64-bit system server spawns a 32-bit child that thinks it should + // enable some tagging variant. Theoretically, a 32-bit system server could exist that + // spawns 64-bit processes, in which case the new process won't get any tagging. This is + // fine as we haven't seen this configuration in practice, and we can reasonable assume + // that if tagging is desired, the system server will be 64-bit. + if (instructionSet == null || instructionSet.equals("arm64")) { + runtimeFlags |= decideTaggingLevel(info, processInfo, platformCompat); + } + if (enableNativeHeapZeroInit(info, processInfo, platformCompat)) { + runtimeFlags |= NATIVE_HEAP_ZERO_INIT_ENABLED; + } + return runtimeFlags; + } + + /** + * Returns Zygote runtimeFlags for memory safety features (MTE, GWP-ASan, nativeHeadZeroInit) + * for a secondary zygote (AppZygote or WebViewZygote). + */ + public static int getMemorySafetyRuntimeFlagsForSecondaryZygote( + @NonNull ApplicationInfo info, @Nullable ProcessInfo processInfo) { + final IPlatformCompat platformCompat = + IPlatformCompat.Stub.asInterface( + ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); + int runtimeFlags = + getMemorySafetyRuntimeFlags( + info, processInfo, null /*instructionSet*/, platformCompat); + + // TBI ("fake" pointer tagging) in AppZygote is controlled by a separate compat feature. + if ((runtimeFlags & MEMORY_TAG_LEVEL_MASK) == MEMORY_TAG_LEVEL_TBI + && isCompatChangeEnabled( + NATIVE_HEAP_POINTER_TAGGING_SECONDARY_ZYGOTE, + info, + platformCompat, + Build.VERSION_CODES.S)) { + // Reset memory tag level to NONE. + runtimeFlags &= ~MEMORY_TAG_LEVEL_MASK; + runtimeFlags |= MEMORY_TAG_LEVEL_NONE; + } + return runtimeFlags; + } } diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 597167026d19f..5b7092cabfcbb 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -346,7 +346,7 @@ enum RuntimeFlags : uint32_t { GWP_ASAN_LEVEL_NEVER = 0 << 21, GWP_ASAN_LEVEL_LOTTERY = 1 << 21, GWP_ASAN_LEVEL_ALWAYS = 2 << 21, - NATIVE_HEAP_ZERO_INIT = 1 << 23, + NATIVE_HEAP_ZERO_INIT_ENABLED = 1 << 23, PROFILEABLE = 1 << 24, }; @@ -1709,13 +1709,13 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, // would be nice to have them for apps, we will have to wait until they are // proven out, have more efficient hardware, and/or apply them only to new // applications. - if (!(runtime_flags & RuntimeFlags::NATIVE_HEAP_ZERO_INIT)) { + if (!(runtime_flags & RuntimeFlags::NATIVE_HEAP_ZERO_INIT_ENABLED)) { mallopt(M_BIONIC_ZERO_INIT, 0); } // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART // runtime. - runtime_flags &= ~RuntimeFlags::NATIVE_HEAP_ZERO_INIT; + runtime_flags &= ~RuntimeFlags::NATIVE_HEAP_ZERO_INIT_ENABLED; bool forceEnableGwpAsan = false; switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) { diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 38f6e6d9f165b..d4ad718fbe730 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -4139,7 +4139,8 @@ public final class ActiveServices { final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0; final String procName = r.processName; - HostingRecord hostingRecord = new HostingRecord("service", r.instanceName); + HostingRecord hostingRecord = new HostingRecord("service", r.instanceName, + r.definingPackageName, r.definingUid, r.serviceInfo.processName); ProcessRecord app; if (!isolated) { @@ -4177,11 +4178,12 @@ public final class ActiveServices { app = r.isolationHostProc; if (WebViewZygote.isMultiprocessEnabled() && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) { - hostingRecord = HostingRecord.byWebviewZygote(r.instanceName); + hostingRecord = HostingRecord.byWebviewZygote(r.instanceName, r.definingPackageName, + r.definingUid, r.serviceInfo.processName); } if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) { hostingRecord = HostingRecord.byAppZygote(r.instanceName, r.definingPackageName, - r.definingUid); + r.definingUid, r.serviceInfo.processName); } } diff --git a/services/core/java/com/android/server/am/HostingRecord.java b/services/core/java/com/android/server/am/HostingRecord.java index 6bb5def26b9d0..bbf586123e1c3 100644 --- a/services/core/java/com/android/server/am/HostingRecord.java +++ b/services/core/java/com/android/server/am/HostingRecord.java @@ -56,19 +56,27 @@ public final class HostingRecord { private final String mDefiningPackageName; private final int mDefiningUid; private final boolean mIsTopApp; + private final String mDefiningProcessName; public HostingRecord(String hostingType) { this(hostingType, null /* hostingName */, REGULAR_ZYGOTE, null /* definingPackageName */, - -1 /* mDefiningUid */, false /* isTopApp */); + -1 /* mDefiningUid */, false /* isTopApp */, null /* definingProcessName */); } public HostingRecord(String hostingType, ComponentName hostingName) { this(hostingType, hostingName, REGULAR_ZYGOTE); } + public HostingRecord(String hostingType, ComponentName hostingName, String definingPackageName, + int definingUid, String definingProcessName) { + this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE, definingPackageName, + definingUid, false /* isTopApp */, definingProcessName); + } + public HostingRecord(String hostingType, ComponentName hostingName, boolean isTopApp) { this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE, - null /* definingPackageName */, -1 /* mDefiningUid */, isTopApp /* isTopApp */); + null /* definingPackageName */, -1 /* mDefiningUid */, isTopApp /* isTopApp */, + null /* definingProcessName */); } public HostingRecord(String hostingType, String hostingName) { @@ -81,17 +89,19 @@ public final class HostingRecord { private HostingRecord(String hostingType, String hostingName, int hostingZygote) { this(hostingType, hostingName, hostingZygote, null /* definingPackageName */, - -1 /* mDefiningUid */, false /* isTopApp */); + -1 /* mDefiningUid */, false /* isTopApp */, null /* definingProcessName */); } private HostingRecord(String hostingType, String hostingName, int hostingZygote, - String definingPackageName, int definingUid, boolean isTopApp) { + String definingPackageName, int definingUid, boolean isTopApp, + String definingProcessName) { mHostingType = hostingType; mHostingName = hostingName; mHostingZygote = hostingZygote; mDefiningPackageName = definingPackageName; mDefiningUid = definingUid; mIsTopApp = isTopApp; + mDefiningProcessName = definingProcessName; } public String getType() { @@ -126,13 +136,25 @@ public final class HostingRecord { return mDefiningPackageName; } + /** + * Returns the processName of the component we want to start as specified in the defining app's + * manifest. + * + * @return the processName of the process in the hosting application + */ + public String getDefiningProcessName() { + return mDefiningProcessName; + } + /** * Creates a HostingRecord for a process that must spawn from the webview zygote * @param hostingName name of the component to be hosted in this process * @return The constructed HostingRecord */ - public static HostingRecord byWebviewZygote(ComponentName hostingName) { - return new HostingRecord("", hostingName.toShortString(), WEBVIEW_ZYGOTE); + public static HostingRecord byWebviewZygote(ComponentName hostingName, + String definingPackageName, int definingUid, String definingProcessName) { + return new HostingRecord("", hostingName.toShortString(), WEBVIEW_ZYGOTE, + definingPackageName, definingUid, false /* isTopApp */, definingProcessName); } /** @@ -143,9 +165,9 @@ public final class HostingRecord { * @return The constructed HostingRecord */ public static HostingRecord byAppZygote(ComponentName hostingName, String definingPackageName, - int definingUid) { + int definingUid, String definingProcessName) { return new HostingRecord("", hostingName.toShortString(), APP_ZYGOTE, - definingPackageName, definingUid, false /* isTopApp */); + definingPackageName, definingUid, false /* isTopApp */, definingProcessName); } /** diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 41cd61da022a0..2c2e7c40c9c35 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -70,7 +70,6 @@ import android.app.IApplicationThread; import android.app.IProcessObserver; import android.app.IUidObserver; import android.compat.annotation.ChangeId; -import android.compat.annotation.Disabled; import android.compat.annotation.EnabledAfter; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -362,59 +361,6 @@ public final class ProcessList { // lmkd reconnect delay in msecs private static final long LMKD_RECONNECT_DELAY_MS = 1000; - /** - * Native heap allocations will now have a non-zero tag in the most significant byte. - * @see Tagged - * Pointers - */ - @ChangeId - @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) - private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id. - - /** - * Native heap allocations in AppZygote process and its descendants will now have a - * non-zero tag in the most significant byte. - * @see Tagged - * Pointers - */ - @ChangeId - @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S) - private static final long NATIVE_HEAP_POINTER_TAGGING_APP_ZYGOTE = 207557677; - - /** - * Enable asynchronous (ASYNC) memory tag checking in this process. This - * flag will only have an effect on hardware supporting the ARM Memory - * Tagging Extension (MTE). - */ - @ChangeId - @Disabled - private static final long NATIVE_MEMTAG_ASYNC = 135772972; // This is a bug id. - - /** - * Enable synchronous (SYNC) memory tag checking in this process. This flag - * will only have an effect on hardware supporting the ARM Memory Tagging - * Extension (MTE). If both NATIVE_MEMTAG_ASYNC and this option is selected, - * this option takes preference and MTE is enabled in SYNC mode. - */ - @ChangeId - @Disabled - private static final long NATIVE_MEMTAG_SYNC = 177438394; // This is a bug id. - - /** - * Enable automatic zero-initialization of native heap memory allocations. - */ - @ChangeId - @Disabled - private static final long NATIVE_HEAP_ZERO_INIT = 178038272; // This is a bug id. - - /** - * Enable sampled memory bug detection in the app. - * @see GWP-ASan. - */ - @ChangeId - @Disabled - private static final long GWP_ASAN = 135634846; // This is a bug id. - /** * Apps have no access to the private data directories of any other app, even if the other * app has made them world-readable. @@ -1681,136 +1627,6 @@ public final class ProcessList { return gidArray; } - private int memtagModeToZygoteMemtagLevel(int memtagMode) { - switch (memtagMode) { - case ApplicationInfo.MEMTAG_ASYNC: - return Zygote.MEMORY_TAG_LEVEL_ASYNC; - case ApplicationInfo.MEMTAG_SYNC: - return Zygote.MEMORY_TAG_LEVEL_SYNC; - default: - return Zygote.MEMORY_TAG_LEVEL_NONE; - } - } - - // Returns the requested memory tagging level. - private int getRequestedMemtagLevel(ProcessRecord app) { - // Look at the process attribute first. - if (app.processInfo != null - && app.processInfo.memtagMode != ApplicationInfo.MEMTAG_DEFAULT) { - return memtagModeToZygoteMemtagLevel(app.processInfo.memtagMode); - } - - // Then at the application attribute. - if (app.info.getMemtagMode() != ApplicationInfo.MEMTAG_DEFAULT) { - return memtagModeToZygoteMemtagLevel(app.info.getMemtagMode()); - } - - if (mPlatformCompat.isChangeEnabled(NATIVE_MEMTAG_SYNC, app.info)) { - return Zygote.MEMORY_TAG_LEVEL_SYNC; - } - - if (mPlatformCompat.isChangeEnabled(NATIVE_MEMTAG_ASYNC, app.info)) { - return Zygote.MEMORY_TAG_LEVEL_ASYNC; - } - - // Check to ensure the app hasn't explicitly opted-out of TBI via. the manifest attribute. - if (!app.info.allowsNativeHeapPointerTagging()) { - return Zygote.MEMORY_TAG_LEVEL_NONE; - } - - String defaultLevel = SystemProperties.get("persist.arm64.memtag.app_default"); - if ("sync".equals(defaultLevel)) { - return Zygote.MEMORY_TAG_LEVEL_SYNC; - } else if ("async".equals(defaultLevel)) { - return Zygote.MEMORY_TAG_LEVEL_ASYNC; - } - - // Check to see that the compat feature for TBI is enabled. - if (mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING, app.info)) { - return Zygote.MEMORY_TAG_LEVEL_TBI; - } - - return Zygote.MEMORY_TAG_LEVEL_NONE; - } - - private int decideTaggingLevel(ProcessRecord app) { - // Get the desired tagging level (app manifest + compat features). - int level = getRequestedMemtagLevel(app); - - // Take into account the hardware capabilities. - if (Zygote.nativeSupportsMemoryTagging()) { - // MTE devices can not do TBI, because the Zygote process already has live MTE - // allocations. Downgrade TBI to NONE. - if (level == Zygote.MEMORY_TAG_LEVEL_TBI) { - level = Zygote.MEMORY_TAG_LEVEL_NONE; - } - } else if (Zygote.nativeSupportsTaggedPointers()) { - // TBI-but-not-MTE devices downgrade MTE modes to TBI. - // The idea is that if an app opts into full hardware tagging (MTE), it must be ok with - // the "fake" pointer tagging (TBI). - if (level == Zygote.MEMORY_TAG_LEVEL_ASYNC || level == Zygote.MEMORY_TAG_LEVEL_SYNC) { - level = Zygote.MEMORY_TAG_LEVEL_TBI; - } - } else { - // Otherwise disable all tagging. - level = Zygote.MEMORY_TAG_LEVEL_NONE; - } - - return level; - } - - private int decideTaggingLevelForAppZygote(ProcessRecord app) { - int level = decideTaggingLevel(app); - // TBI ("fake" pointer tagging) in AppZygote is controlled by a separate compat feature. - if (!mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING_APP_ZYGOTE, app.info) - && level == Zygote.MEMORY_TAG_LEVEL_TBI) { - level = Zygote.MEMORY_TAG_LEVEL_NONE; - } - return level; - } - - private int decideGwpAsanLevel(ProcessRecord app) { - // Look at the process attribute first. - if (app.processInfo != null - && app.processInfo.gwpAsanMode != ApplicationInfo.GWP_ASAN_DEFAULT) { - return app.processInfo.gwpAsanMode == ApplicationInfo.GWP_ASAN_ALWAYS - ? Zygote.GWP_ASAN_LEVEL_ALWAYS - : Zygote.GWP_ASAN_LEVEL_NEVER; - } - // Then at the application attribute. - if (app.info.getGwpAsanMode() != ApplicationInfo.GWP_ASAN_DEFAULT) { - return app.info.getGwpAsanMode() == ApplicationInfo.GWP_ASAN_ALWAYS - ? Zygote.GWP_ASAN_LEVEL_ALWAYS - : Zygote.GWP_ASAN_LEVEL_NEVER; - } - // If the app does not specify gwpAsanMode, the default behavior is lottery among the - // system apps, and disabled for user apps, unless overwritten by the compat feature. - if (mPlatformCompat.isChangeEnabled(GWP_ASAN, app.info)) { - return Zygote.GWP_ASAN_LEVEL_ALWAYS; - } - if ((app.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { - return Zygote.GWP_ASAN_LEVEL_LOTTERY; - } - return Zygote.GWP_ASAN_LEVEL_NEVER; - } - - private boolean enableNativeHeapZeroInit(ProcessRecord app) { - // Look at the process attribute first. - if (app.processInfo != null - && app.processInfo.nativeHeapZeroInitialized != ApplicationInfo.ZEROINIT_DEFAULT) { - return app.processInfo.nativeHeapZeroInitialized == ApplicationInfo.ZEROINIT_ENABLED; - } - // Then at the application attribute. - if (app.info.getNativeHeapZeroInitialized() != ApplicationInfo.ZEROINIT_DEFAULT) { - return app.info.getNativeHeapZeroInitialized() == ApplicationInfo.ZEROINIT_ENABLED; - } - // Compat feature last. - if (mPlatformCompat.isChangeEnabled(NATIVE_HEAP_ZERO_INIT, app.info)) { - return true; - } - return false; - } - /** * @return {@code true} if process start is successful, false otherwise. */ @@ -1992,8 +1808,6 @@ public final class ProcessList { runtimeFlags |= Zygote.USE_APP_IMAGE_STARTUP_CACHE; } - runtimeFlags |= decideGwpAsanLevel(app); - String invokeWith = null; if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) { // Debuggable apps may include a wrapper script with their library directory. @@ -2024,23 +1838,21 @@ public final class ProcessList { app.setRequiredAbi(requiredAbi); app.setInstructionSet(instructionSet); - // If instructionSet is non-null, this indicates that the system_server is spawning a - // process with an ISA that may be different from its own. System (kernel and hardware) - // compatibility for these features is checked in the decideTaggingLevel in the - // system_server process (not the child process). As both MTE and TBI are only supported - // in aarch64, we can simply ensure that the new process is also aarch64. This prevents - // the mismatch where a 64-bit system server spawns a 32-bit child that thinks it should - // enable some tagging variant. Theoretically, a 32-bit system server could exist that - // spawns 64-bit processes, in which case the new process won't get any tagging. This is - // fine as we haven't seen this configuration in practice, and we can reasonable assume - // that if tagging is desired, the system server will be 64-bit. - if (instructionSet == null || instructionSet.equals("arm64")) { - runtimeFlags |= decideTaggingLevel(app); + // If this was an external service, the package name and uid in the passed in + // ApplicationInfo have been changed to match those of the calling package; + // that will incorrectly apply compat feature overrides for the calling package instead + // of the defining one. + ApplicationInfo definingAppInfo; + if (hostingRecord.getDefiningPackageName() != null) { + definingAppInfo = new ApplicationInfo(app.info); + definingAppInfo.packageName = hostingRecord.getDefiningPackageName(); + definingAppInfo.uid = uid; + } else { + definingAppInfo = app.info; } - if (enableNativeHeapZeroInit(app)) { - runtimeFlags |= Zygote.NATIVE_HEAP_ZERO_INIT; - } + runtimeFlags |= Zygote.getMemorySafetyRuntimeFlags( + definingAppInfo, app.processInfo, instructionSet, mPlatformCompat); // the per-user SELinux context must be set if (TextUtils.isEmpty(app.info.seInfoUser)) { @@ -2299,8 +2111,7 @@ public final class ProcessList { // not the calling one. appInfo.packageName = app.getHostingRecord().getDefiningPackageName(); appInfo.uid = uid; - int runtimeFlags = decideTaggingLevelForAppZygote(app); - appZygote = new AppZygote(appInfo, uid, firstUid, lastUid, runtimeFlags); + appZygote = new AppZygote(appInfo, app.processInfo, uid, firstUid, lastUid); mAppZygotes.put(app.info.processName, uid, appZygote); zygoteProcessList = new ArrayList(); mAppZygoteProcesses.put(appZygote, zygoteProcessList); @@ -3158,7 +2969,8 @@ public final class ProcessList { FrameworkStatsLog.write(FrameworkStatsLog.ISOLATED_UID_CHANGED, info.uid, uid, FrameworkStatsLog.ISOLATED_UID_CHANGED__EVENT__CREATED); } - final ProcessRecord r = new ProcessRecord(mService, info, proc, uid); + final ProcessRecord r = new ProcessRecord(mService, info, proc, uid, + hostingRecord.getDefiningUid(), hostingRecord.getDefiningProcessName()); final ProcessStateRecord state = r.mState; if (!mService.mBooted && !mService.mBooting diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index be187e21db47d..7672d10e27bd0 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -492,24 +492,33 @@ class ProcessRecord implements WindowProcessListener { ProcessRecord(ActivityManagerService _service, ApplicationInfo _info, String _processName, int _uid) { + this(_service, _info, _processName, _uid, -1, null); + } + + ProcessRecord(ActivityManagerService _service, ApplicationInfo _info, String _processName, + int _uid, int _definingUid, String _definingProcessName) { mService = _service; mProcLock = _service.mProcLock; info = _info; ProcessInfo procInfo = null; if (_service.mPackageManagerInt != null) { - ArrayMap processes = - _service.mPackageManagerInt.getProcessesForUid(_uid); - if (processes != null) { - procInfo = processes.get(_processName); - if (procInfo != null && procInfo.deniedPermissions == null - && procInfo.gwpAsanMode == ApplicationInfo.GWP_ASAN_DEFAULT - && procInfo.memtagMode == ApplicationInfo.MEMTAG_DEFAULT - && procInfo.nativeHeapZeroInitialized == ApplicationInfo.ZEROINIT_DEFAULT) { - // If this process hasn't asked for permissions to be denied, or for a - // non-default GwpAsan mode, or any other non-default setting, then we don't - // care about it. - procInfo = null; - } + if (_definingUid > 0) { + ArrayMap processes = + _service.mPackageManagerInt.getProcessesForUid(_definingUid); + if (processes != null) procInfo = processes.get(_definingProcessName); + } else { + ArrayMap processes = + _service.mPackageManagerInt.getProcessesForUid(_uid); + if (processes != null) procInfo = processes.get(_processName); + } + if (procInfo != null && procInfo.deniedPermissions == null + && procInfo.gwpAsanMode == ApplicationInfo.GWP_ASAN_DEFAULT + && procInfo.memtagMode == ApplicationInfo.MEMTAG_DEFAULT + && procInfo.nativeHeapZeroInitialized == ApplicationInfo.ZEROINIT_DEFAULT) { + // If this process hasn't asked for permissions to be denied, or for a + // non-default GwpAsan mode, or any other non-default setting, then we don't + // care about it. + procInfo = null; } } processInfo = procInfo; diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java index 26b5218d2ab4f..4a40b5f2de7b2 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java @@ -1000,7 +1000,7 @@ public class ApplicationExitInfoTest { final String dummyPackageName = "com.android.test"; final String dummyClassName = ".Foo"; app.setHostingRecord(HostingRecord.byAppZygote(new ComponentName( - dummyPackageName, dummyClassName), "", definingUid)); + dummyPackageName, dummyClassName), "", definingUid, "")); } app.mServices.setConnectionGroup(connectionGroup); app.mState.setReportedProcState(procState);