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);