Fix memory flags in external services and secondary zygotes.
This change fixes a number of interconnected issues in memory safety (MTE, GWP-ASan, nativeHeapZeroInit) runtime flags. * Exported services use the hosting app UID to locate the process definition, and fail 100% of the time. Use the defining app UID and package name instead. * Isolated services process name does not match the name in the defining app manifest, because it includes a class name and an instance number. Pass the defining process name in HostingRecord to address this. * Exported service ApplicationInfo.packageName refers to the hosting app, again. As a result, wrong compat feature overrides are applied. This has been fixed before for AppZygote services; extend the fix to all external services. * Pass correct memory runtimeFlags to WebViewZygote. This is important because both MTE and GWP-ASan have a one-way disable switch; they are enabled in the Zygote and disabled in the apps that do not opt-in. Passing 0 runtimeFlags to WebViewZygote (and AppZygote) makes it impossible to enable these features later in their child processes. This change moves runtimeFlags logic from ProcessList to os.Zygote to make it available to WebViewZygote. Bug: 208910418 Test: CtsTaggingHostTestCases Test: atest in frameworks/base Test: CtsWebkitTestCases Test: manual install WebView with android:memtagMode tag Change-Id: I232d35344f4cd34226ff11324421904b35251525
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged
|
||||
* Pointers</a>
|
||||
*/
|
||||
@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 <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged
|
||||
* Pointers</a>
|
||||
*/
|
||||
@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 <a href="https://source.android.com/devices/tech/debug/gwp-asan">GWP-ASan</a>.
|
||||
*/
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged
|
||||
* Pointers</a>
|
||||
*/
|
||||
@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 <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged
|
||||
* Pointers</a>
|
||||
*/
|
||||
@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 <a href="https://source.android.com/devices/tech/debug/gwp-asan">GWP-ASan</a>.
|
||||
*/
|
||||
@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<ProcessRecord>();
|
||||
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
|
||||
|
||||
@@ -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<String, ProcessInfo> 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<String, ProcessInfo> processes =
|
||||
_service.mPackageManagerInt.getProcessesForUid(_definingUid);
|
||||
if (processes != null) procInfo = processes.get(_definingProcessName);
|
||||
} else {
|
||||
ArrayMap<String, ProcessInfo> 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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user