From 15cce113f7232e117b091770c220ebc1b55f41d2 Mon Sep 17 00:00:00 2001 From: Evgenii Stepanov Date: Fri, 15 Jan 2021 14:11:47 -0800 Subject: [PATCH] Implement memtagMode and nativeHeapZeroInit manifest attrs. memtagMode allows an app to opt in to MTE in either sync or async mode. nativeHeapZeroInit enables automatic initialization of heap memory. Both attributes default to off and can be specified at either application or process level. Bug: 135772972 Bug: 177438394 Bug: 178038272 Test: CtsTaggingHostTestCases Change-Id: I6a481a9d2363997bf954f248d08224c79f0c2afb Merged-In: I6a481a9d2363997bf954f248d08224c79f0c2afb --- core/api/current.txt | 8 ++ .../android/content/pm/ApplicationInfo.java | 73 ++++++++++++ core/java/android/content/pm/ProcessInfo.java | 44 ++++++- .../content/pm/parsing/ParsingPackage.java | 4 + .../pm/parsing/ParsingPackageImpl.java | 34 ++++++ .../pm/parsing/ParsingPackageRead.java | 13 ++ .../pm/parsing/ParsingPackageUtils.java | 5 + .../pm/parsing/component/ParsedProcess.java | 40 ++++++- .../parsing/component/ParsedProcessUtils.java | 5 + core/java/com/android/internal/os/Zygote.java | 7 ++ core/jni/com_android_internal_os_Zygote.cpp | 10 +- .../android/content/package_item_info.proto | 2 + core/res/res/values/attrs_manifest.xml | 13 ++ core/res/res/values/public.xml | 2 + .../com/android/server/am/ProcessList.java | 112 ++++++++++++------ .../com/android/server/am/ProcessRecord.java | 10 +- .../server/pm/parsing/PackageInfoUtils.java | 3 +- 17 files changed, 336 insertions(+), 49 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index 80c555bd15b94..5f2555a20f75e 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -954,6 +954,7 @@ package android { field public static final int measureWithLargestChild = 16843476; // 0x10102d4 field public static final int mediaRouteButtonStyle = 16843693; // 0x10103ad field public static final int mediaRouteTypes = 16843694; // 0x10103ae + field public static final int memtagMode = 16844313; // 0x1010619 field public static final int menuCategory = 16843230; // 0x10101de field public static final int mimeGroup = 16844309; // 0x1010615 field public static final int mimeType = 16842790; // 0x1010026 @@ -977,6 +978,7 @@ package android { field public static final int multiArch = 16843918; // 0x101048e field public static final int multiprocess = 16842771; // 0x1010013 field public static final int name = 16842755; // 0x1010003 + field public static final int nativeHeapZeroInit = 16844314; // 0x101061a field public static final int navigationBarColor = 16843858; // 0x1010452 field public static final int navigationBarDividerColor = 16844141; // 0x101056d field public static final int navigationContentDescription = 16843969; // 0x10104c1 @@ -11461,6 +11463,8 @@ package android.content.pm { method public void dump(android.util.Printer, String); method public static CharSequence getCategoryTitle(android.content.Context, int); method public int getGwpAsanMode(); + method public int getMemtagMode(); + method @Nullable public Boolean isNativeHeapZeroInit(); method public boolean isProfileableByShell(); method public boolean isResourceOverlay(); method public boolean isVirtualPreload(); @@ -11510,6 +11514,10 @@ package android.content.pm { field public static final int GWP_ASAN_ALWAYS = 1; // 0x1 field public static final int GWP_ASAN_DEFAULT = -1; // 0xffffffff field public static final int GWP_ASAN_NEVER = 0; // 0x0 + field public static final int MEMTAG_ASYNC = 1; // 0x1 + field public static final int MEMTAG_DEFAULT = -1; // 0xffffffff + field public static final int MEMTAG_OFF = 0; // 0x0 + field public static final int MEMTAG_SYNC = 2; // 0x2 field public String appComponentFactory; field public String backupAgentName; field public int category; diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index e32068fe4b397..6ec11693d69b8 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -38,6 +38,8 @@ import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.Parcelling; +import com.android.internal.util.Parcelling.BuiltIn.ForBoolean; import com.android.server.SystemConfig; import java.lang.annotation.Retention; @@ -56,6 +58,8 @@ import java.util.UUID; * <application> tag. */ public class ApplicationInfo extends PackageItemInfo implements Parcelable { + private static ForBoolean sForBoolean = Parcelling.Cache.getOrCreate(ForBoolean.class); + /** * Default task affinity of all activities in this application. See * {@link ActivityInfo#taskAffinity} for more information. This comes @@ -1335,6 +1339,51 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ private @GwpAsanMode int gwpAsanMode; + /** + * Default (unspecified) setting of Memtag. + */ + public static final int MEMTAG_DEFAULT = -1; + + /** + * Do not enable Memtag in this application or process. + */ + public static final int MEMTAG_OFF = 0; + + /** + * Enable Memtag in Async mode in this application or process. + */ + public static final int MEMTAG_ASYNC = 1; + + /** + * Enable Memtag in Sync mode in this application or process. + */ + public static final int MEMTAG_SYNC = 2; + + /** + * These constants need to match the values of memtagMode in application manifest. + * @hide + */ + @IntDef(prefix = {"MEMTAG_"}, value = { + MEMTAG_DEFAULT, + MEMTAG_OFF, + MEMTAG_ASYNC, + MEMTAG_SYNC, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface MemtagMode {} + + /** + * Indicates if the application has requested Memtag to be enabled, disabled, or left + * unspecified. Processes can override this setting. + */ + private @MemtagMode int memtagMode; + + /** + * Enable automatic zero-initialization of native heap memory allocations. + */ + @Nullable + private Boolean nativeHeapZeroInit; + /** * Represents the default policy. The actual policy used will depend on other properties of * the application, e.g. the target SDK version. @@ -1479,6 +1528,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { if (gwpAsanMode != GWP_ASAN_DEFAULT) { pw.println(prefix + "gwpAsanMode=" + gwpAsanMode); } + if (memtagMode != MEMTAG_DEFAULT) { + pw.println(prefix + "memtagMode=" + memtagMode); + } + if (nativeHeapZeroInit != null) { + pw.println(prefix + "nativeHeapZeroInit=" + nativeHeapZeroInit); + } } super.dumpBack(pw, prefix); } @@ -1580,6 +1635,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { if (gwpAsanMode != GWP_ASAN_DEFAULT) { proto.write(ApplicationInfoProto.Detail.ENABLE_GWP_ASAN, gwpAsanMode); } + if (memtagMode != MEMTAG_DEFAULT) { + proto.write(ApplicationInfoProto.Detail.ENABLE_MEMTAG, memtagMode); + } + if (nativeHeapZeroInit != null) { + proto.write(ApplicationInfoProto.Detail.NATIVE_HEAP_ZERO_INIT, nativeHeapZeroInit); + } proto.end(detailToken); } proto.end(token); @@ -1690,6 +1751,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { hiddenUntilInstalled = orig.hiddenUntilInstalled; zygotePreloadName = orig.zygotePreloadName; gwpAsanMode = orig.gwpAsanMode; + memtagMode = orig.memtagMode; + nativeHeapZeroInit = orig.nativeHeapZeroInit; } public String toString() { @@ -1774,6 +1837,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeInt(hiddenUntilInstalled ? 1 : 0); dest.writeString8(zygotePreloadName); dest.writeInt(gwpAsanMode); + dest.writeInt(memtagMode); + sForBoolean.parcel(nativeHeapZeroInit, dest, parcelableFlags); } public static final @android.annotation.NonNull Parcelable.Creator CREATOR @@ -1855,6 +1920,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { hiddenUntilInstalled = source.readInt() != 0; zygotePreloadName = source.readString8(); gwpAsanMode = source.readInt(); + memtagMode = source.readInt(); + nativeHeapZeroInit = sForBoolean.unparcel(source); } /** @@ -2237,6 +2304,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { /** {@hide} */ public void setBaseResourcePath(String baseResourcePath) { publicSourceDir = baseResourcePath; } /** {@hide} */ public void setSplitResourcePaths(String[] splitResourcePaths) { splitPublicSourceDirs = splitResourcePaths; } /** {@hide} */ public void setGwpAsanMode(@GwpAsanMode int value) { gwpAsanMode = value; } + /** {@hide} */ public void setMemtagMode(@MemtagMode int value) { memtagMode = value; } + /** {@hide} */ public void setNativeHeapZeroInit(@Nullable Boolean value) { nativeHeapZeroInit = value; } /** {@hide} */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -2250,4 +2319,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { /** {@hide} */ public String[] getSplitResourcePaths() { return splitPublicSourceDirs; } @GwpAsanMode public int getGwpAsanMode() { return gwpAsanMode; } + @MemtagMode + public int getMemtagMode() { return memtagMode; } + @Nullable + public Boolean isNativeHeapZeroInit() { return nativeHeapZeroInit; } } diff --git a/core/java/android/content/pm/ProcessInfo.java b/core/java/android/content/pm/ProcessInfo.java index d45ff98d58e43..3dd5ee1020904 100644 --- a/core/java/android/content/pm/ProcessInfo.java +++ b/core/java/android/content/pm/ProcessInfo.java @@ -53,16 +53,30 @@ public class ProcessInfo implements Parcelable { */ public @ApplicationInfo.GwpAsanMode int gwpAsanMode; + /** + * Indicates if the process has requested Memtag to be enabled (in sync or async mode), + * disabled, or left unspecified. + */ + public @ApplicationInfo.MemtagMode int memtagMode; + + /** + * Enable automatic zero-initialization of native heap memory allocations. + */ + @Nullable + public Boolean nativeHeapZeroInit; + @Deprecated public ProcessInfo(@NonNull ProcessInfo orig) { this.name = orig.name; this.deniedPermissions = orig.deniedPermissions; this.gwpAsanMode = orig.gwpAsanMode; + this.memtagMode = orig.memtagMode; + this.nativeHeapZeroInit = orig.nativeHeapZeroInit; } - // Code below generated by codegen v1.0.15. + // Code below generated by codegen v1.0.22. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -84,12 +98,19 @@ public class ProcessInfo implements Parcelable { * If non-null, these are permissions that are not allowed in this process. * @param gwpAsanMode * Indicates if the process has requested GWP-ASan to be enabled, disabled, or left unspecified. + * @param memtagMode + * Indicates if the process has requested Memtag to be enabled (in sync or async mode), + * disabled, or left unspecified. + * @param nativeHeapZeroInit + * Enable automatic zero-initialization of native heap memory allocations. */ @DataClass.Generated.Member public ProcessInfo( @NonNull String name, @Nullable ArraySet deniedPermissions, - @ApplicationInfo.GwpAsanMode int gwpAsanMode) { + @ApplicationInfo.GwpAsanMode int gwpAsanMode, + @ApplicationInfo.MemtagMode int memtagMode, + @Nullable Boolean nativeHeapZeroInit) { this.name = name; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, name); @@ -97,6 +118,10 @@ public class ProcessInfo implements Parcelable { this.gwpAsanMode = gwpAsanMode; com.android.internal.util.AnnotationValidations.validate( ApplicationInfo.GwpAsanMode.class, null, gwpAsanMode); + this.memtagMode = memtagMode; + com.android.internal.util.AnnotationValidations.validate( + ApplicationInfo.MemtagMode.class, null, memtagMode); + this.nativeHeapZeroInit = nativeHeapZeroInit; // onConstructed(); // You can define this method to get a callback } @@ -120,10 +145,13 @@ public class ProcessInfo implements Parcelable { byte flg = 0; if (deniedPermissions != null) flg |= 0x2; + if (nativeHeapZeroInit != null) flg |= 0x10; dest.writeByte(flg); dest.writeString(name); sParcellingForDeniedPermissions.parcel(deniedPermissions, dest, flags); dest.writeInt(gwpAsanMode); + dest.writeInt(memtagMode); + if (nativeHeapZeroInit != null) dest.writeBoolean(nativeHeapZeroInit); } @Override @@ -141,6 +169,8 @@ public class ProcessInfo implements Parcelable { String _name = in.readString(); ArraySet _deniedPermissions = sParcellingForDeniedPermissions.unparcel(in); int _gwpAsanMode = in.readInt(); + int _memtagMode = in.readInt(); + Boolean _nativeHeapZeroInit = (flg & 0x10) == 0 ? null : (Boolean) in.readBoolean(); this.name = _name; com.android.internal.util.AnnotationValidations.validate( @@ -149,6 +179,10 @@ public class ProcessInfo implements Parcelable { this.gwpAsanMode = _gwpAsanMode; com.android.internal.util.AnnotationValidations.validate( ApplicationInfo.GwpAsanMode.class, null, gwpAsanMode); + this.memtagMode = _memtagMode; + com.android.internal.util.AnnotationValidations.validate( + ApplicationInfo.MemtagMode.class, null, memtagMode); + this.nativeHeapZeroInit = _nativeHeapZeroInit; // onConstructed(); // You can define this method to get a callback } @@ -168,10 +202,10 @@ public class ProcessInfo implements Parcelable { }; @DataClass.Generated( - time = 1584555730519L, - codegenVersion = "1.0.15", + time = 1611614699049L, + codegenVersion = "1.0.22", sourceFile = "frameworks/base/core/java/android/content/pm/ProcessInfo.java", - inputSignatures = "public @android.annotation.NonNull java.lang.String name\npublic @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringArraySet.class) android.util.ArraySet deniedPermissions\npublic @android.content.pm.ApplicationInfo.GwpAsanMode int gwpAsanMode\nclass ProcessInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)") + inputSignatures = "public @android.annotation.NonNull java.lang.String name\npublic @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringArraySet.class) android.util.ArraySet deniedPermissions\npublic @android.content.pm.ApplicationInfo.GwpAsanMode int gwpAsanMode\npublic @android.content.pm.ApplicationInfo.MemtagMode int memtagMode\npublic @android.annotation.Nullable java.lang.Boolean nativeHeapZeroInit\nclass ProcessInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)") @Deprecated private void __metadata() {} diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java index 2ee0ad67b108f..983a02ca65764 100644 --- a/core/java/android/content/pm/parsing/ParsingPackage.java +++ b/core/java/android/content/pm/parsing/ParsingPackage.java @@ -241,6 +241,10 @@ public interface ParsingPackage extends ParsingPackageRead { ParsingPackage setGwpAsanMode(int gwpAsanMode); + ParsingPackage setMemtagMode(int memtagMode); + + ParsingPackage setNativeHeapZeroInit(@Nullable Boolean nativeHeapZeroInit); + ParsingPackage setCrossProfile(boolean crossProfile); ParsingPackage setFullBackupContent(int fullBackupContent); diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java index f932bc250e28e..ffc78f3fd9429 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java +++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java @@ -416,6 +416,11 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { private boolean preserveLegacyExternalStorage; protected int gwpAsanMode; + protected int memtagMode; + + @Nullable + @DataClass.ParcelWith(ForBoolean.class) + private Boolean nativeHeapZeroInit; // TODO(chiuwinson): Non-null @Nullable @@ -926,6 +931,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { appInfo.zygotePreloadName = zygotePreloadName; appInfo.crossProfile = isCrossProfile(); appInfo.setGwpAsanMode(gwpAsanMode); + appInfo.setMemtagMode(memtagMode); + appInfo.setNativeHeapZeroInit(nativeHeapZeroInit); appInfo.setBaseCodePath(baseCodePath); appInfo.setBaseResourcePath(baseCodePath); appInfo.setCodePath(codePath); @@ -1110,6 +1117,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { dest.writeArraySet(this.mimeGroups); dest.writeInt(this.gwpAsanMode); dest.writeSparseIntArray(this.minExtensionVersions); + dest.writeInt(this.memtagMode); + sForBoolean.parcel(this.nativeHeapZeroInit, dest, flags); } public ParsingPackageImpl(Parcel in) { @@ -1270,6 +1279,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { this.mimeGroups = (ArraySet) in.readArraySet(boot); this.gwpAsanMode = in.readInt(); this.minExtensionVersions = in.readSparseIntArray(); + this.memtagMode = in.readInt(); + this.nativeHeapZeroInit = sForBoolean.unparcel(in); } public static final Parcelable.Creator CREATOR = @@ -2002,6 +2013,17 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { return gwpAsanMode; } + @Override + public int getMemtagMode() { + return memtagMode; + } + + @Nullable + @Override + public Boolean isNativeHeapZeroInit() { + return nativeHeapZeroInit; + } + @Override public boolean isPartiallyDirectBootAware() { return partiallyDirectBootAware; @@ -2474,6 +2496,18 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { return this; } + @Override + public ParsingPackageImpl setMemtagMode(int value) { + memtagMode = value; + return this; + } + + @Override + public ParsingPackageImpl setNativeHeapZeroInit(@Nullable Boolean value) { + nativeHeapZeroInit = value; + return this; + } + @Override public ParsingPackageImpl setPartiallyDirectBootAware(boolean value) { partiallyDirectBootAware = value; diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java index 5b53c18b820cb..cd91e280b695c 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageRead.java +++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java @@ -856,6 +856,19 @@ public interface ParsingPackageRead extends Parcelable { */ public int getGwpAsanMode(); + /** + * @see ApplicationInfo#memtagMode + * @see R.styleable#AndroidManifest_memtagMode + */ + int getMemtagMode(); + + /** + * @see ApplicationInfo#nativeHeapZeroInit + * @see R.styleable#AndroidManifest_nativeHeapZeroInit + */ + @Nullable + Boolean isNativeHeapZeroInit(); + // TODO(b/135203078): Hide and enforce going through PackageInfoUtils ApplicationInfo toAppInfoWithoutState(); diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index ab0ed51fb909f..890ba8a59a89d 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -1799,6 +1799,11 @@ public class ParsingPackageUtils { } pkg.setGwpAsanMode(sa.getInt(R.styleable.AndroidManifestApplication_gwpAsanMode, -1)); + pkg.setMemtagMode(sa.getInt(R.styleable.AndroidManifestApplication_memtagMode, -1)); + if (sa.hasValue(R.styleable.AndroidManifestApplication_nativeHeapZeroInit)) { + pkg.setNativeHeapZeroInit(sa.getBoolean( + R.styleable.AndroidManifestApplication_nativeHeapZeroInit, false)); + } } finally { sa.recycle(); } diff --git a/core/java/android/content/pm/parsing/component/ParsedProcess.java b/core/java/android/content/pm/parsing/component/ParsedProcess.java index e0ae81b2e30be..89fef9d8e0dde 100644 --- a/core/java/android/content/pm/parsing/component/ParsedProcess.java +++ b/core/java/android/content/pm/parsing/component/ParsedProcess.java @@ -20,6 +20,7 @@ import static java.util.Collections.emptySet; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.pm.ApplicationInfo; import android.os.Parcel; import android.os.Parcelable; import android.util.ArraySet; @@ -41,7 +42,10 @@ public class ParsedProcess implements Parcelable { @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class) protected Set deniedPermissions = emptySet(); - protected int gwpAsanMode = -1; + protected int gwpAsanMode = ApplicationInfo.GWP_ASAN_DEFAULT; + protected int memtagMode = ApplicationInfo.MEMTAG_DEFAULT; + @Nullable + protected Boolean nativeHeapZeroInit = null; public ParsedProcess() { } @@ -57,7 +61,7 @@ public class ParsedProcess implements Parcelable { - // Code below generated by codegen v1.0.15. + // Code below generated by codegen v1.0.22. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -74,7 +78,9 @@ public class ParsedProcess implements Parcelable { public ParsedProcess( @NonNull String name, @NonNull Set deniedPermissions, - int gwpAsanMode) { + int gwpAsanMode, + int memtagMode, + @Nullable Boolean nativeHeapZeroInit) { this.name = name; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, name); @@ -82,6 +88,8 @@ public class ParsedProcess implements Parcelable { com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, deniedPermissions); this.gwpAsanMode = gwpAsanMode; + this.memtagMode = memtagMode; + this.nativeHeapZeroInit = nativeHeapZeroInit; // onConstructed(); // You can define this method to get a callback } @@ -101,6 +109,16 @@ public class ParsedProcess implements Parcelable { return gwpAsanMode; } + @DataClass.Generated.Member + public int getMemtagMode() { + return memtagMode; + } + + @DataClass.Generated.Member + public @Nullable Boolean getNativeHeapZeroInit() { + return nativeHeapZeroInit; + } + @DataClass.Generated.Member static Parcelling> sParcellingForDeniedPermissions = Parcelling.Cache.get( @@ -118,9 +136,14 @@ public class ParsedProcess implements Parcelable { // You can override field parcelling by defining methods like: // void parcelFieldName(Parcel dest, int flags) { ... } + byte flg = 0; + if (nativeHeapZeroInit != null) flg |= 0x10; + dest.writeByte(flg); dest.writeString(name); sParcellingForDeniedPermissions.parcel(deniedPermissions, dest, flags); dest.writeInt(gwpAsanMode); + dest.writeInt(memtagMode); + if (nativeHeapZeroInit != null) dest.writeBoolean(nativeHeapZeroInit); } @Override @@ -134,9 +157,12 @@ public class ParsedProcess implements Parcelable { // You can override field unparcelling by defining methods like: // static FieldType unparcelFieldName(Parcel in) { ... } + byte flg = in.readByte(); String _name = in.readString(); Set _deniedPermissions = sParcellingForDeniedPermissions.unparcel(in); int _gwpAsanMode = in.readInt(); + int _memtagMode = in.readInt(); + Boolean _nativeHeapZeroInit = (flg & 0x10) == 0 ? null : (Boolean) in.readBoolean(); this.name = _name; com.android.internal.util.AnnotationValidations.validate( @@ -145,6 +171,8 @@ public class ParsedProcess implements Parcelable { com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, deniedPermissions); this.gwpAsanMode = _gwpAsanMode; + this.memtagMode = _memtagMode; + this.nativeHeapZeroInit = _nativeHeapZeroInit; // onConstructed(); // You can define this method to get a callback } @@ -164,10 +192,10 @@ public class ParsedProcess implements Parcelable { }; @DataClass.Generated( - time = 1584557524776L, - codegenVersion = "1.0.15", + time = 1611615591258L, + codegenVersion = "1.0.22", sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcess.java", - inputSignatures = "protected @android.annotation.NonNull java.lang.String name\nprotected @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set deniedPermissions\nprotected int gwpAsanMode\npublic void addStateFrom(android.content.pm.parsing.component.ParsedProcess)\nclass ParsedProcess extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)") + inputSignatures = "protected @android.annotation.NonNull java.lang.String name\nprotected @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set deniedPermissions\nprotected int gwpAsanMode\nprotected int memtagMode\nprotected @android.annotation.Nullable java.lang.Boolean nativeHeapZeroInit\npublic void addStateFrom(android.content.pm.parsing.component.ParsedProcess)\nclass ParsedProcess extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)") @Deprecated private void __metadata() {} diff --git a/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java index 8372707210786..082593efd4980 100644 --- a/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java +++ b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java @@ -105,6 +105,11 @@ public class ParsedProcessUtils { } proc.gwpAsanMode = sa.getInt(R.styleable.AndroidManifestProcess_gwpAsanMode, -1); + proc.memtagMode = sa.getInt(R.styleable.AndroidManifestProcess_memtagMode, -1); + if (sa.hasValue(R.styleable.AndroidManifestProcess_nativeHeapZeroInit)) { + proc.nativeHeapZeroInit = + sa.getBoolean(R.styleable.AndroidManifestProcess_nativeHeapZeroInit, false); + } } finally { sa.recycle(); } diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 9abc55b983a06..d99f30567311b 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -123,6 +123,8 @@ public final class Zygote { public static final int DISABLE_TEST_API_ENFORCEMENT_POLICY = 1 << 18; 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. @@ -168,6 +170,11 @@ public final class Zygote { */ public static final int GWP_ASAN_LEVEL_ALWAYS = 2 << 21; + /** + * Enable automatic zero-initialization of native heap memory allocations. + */ + public static final int NATIVE_HEAP_ZERO_INIT = 1 << 23; + /** No external storage should be mounted. */ public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE; /** Default external storage should be mounted. */ diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 4cef2b099589d..bcd203b6ca775 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -344,6 +344,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, }; enum UnsolicitedZygoteMessageTypes : uint32_t { @@ -1682,15 +1683,20 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, } mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level); + // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime. + runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK; + // Avoid heap zero initialization for applications without MTE. Zero init may // cause app compat problems, use more memory, or reduce performance. While it // 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. - mallopt(M_BIONIC_ZERO_INIT, 0); + if (!(runtime_flags & RuntimeFlags::NATIVE_HEAP_ZERO_INIT)) { + 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::MEMORY_TAG_LEVEL_MASK; + runtime_flags &= ~RuntimeFlags::NATIVE_HEAP_ZERO_INIT; bool forceEnableGwpAsan = false; switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) { diff --git a/core/proto/android/content/package_item_info.proto b/core/proto/android/content/package_item_info.proto index e6833066f17ef..bb39ea810add3 100644 --- a/core/proto/android/content/package_item_info.proto +++ b/core/proto/android/content/package_item_info.proto @@ -110,6 +110,8 @@ message ApplicationInfoProto { optional int32 network_security_config_res = 17; optional int32 category = 18; optional int32 enable_gwp_asan = 19; + optional int32 enable_memtag = 20; + optional bool native_heap_zero_init = 21; } optional Detail detail = 17; } diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 0c63c1096a3a0..47dbd64c04023 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1560,6 +1560,13 @@ + + + + + + + @@ -2350,6 +2361,8 @@ + + + + diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index b6e632d42d8ec..c5a6e7b83859f 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -366,6 +366,13 @@ public final class ProcessList { @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. @@ -1687,12 +1694,28 @@ public final class ProcessList { return gidArray; } - // Returns the memory tagging level to be enabled. If memory tagging isn't - // requested, returns zero. - private int getMemtagLevel(ProcessRecord app) { - // Ensure the hardware + kernel actually supports MTE. - if (!Zygote.nativeSupportsMemoryTagging()) { - return 0; + 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)) { @@ -1703,40 +1726,43 @@ public final class ProcessList { return Zygote.MEMORY_TAG_LEVEL_ASYNC; } - return 0; - } - - private boolean shouldEnableTaggedPointers(ProcessRecord app) { - // Ensure we have platform + kernel support for TBI. - if (!Zygote.nativeSupportsTaggedPointers()) { - return false; - } - // Check to ensure the app hasn't explicitly opted-out of TBI via. the manifest attribute. if (!app.info.allowsNativeHeapPointerTagging()) { - return false; + return Zygote.MEMORY_TAG_LEVEL_NONE; } // Check to see that the compat feature for TBI is enabled. - if (!mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING, app.info)) { - return false; - } - - return true; - } - - private int decideTaggingLevel(ProcessRecord app) { - // Check MTE support first, as it should take precedence over TBI. - int memtagLevel = getMemtagLevel(app); - if (memtagLevel != 0) { - return memtagLevel; - } - - if (shouldEnableTaggedPointers(app)) { + if (mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING, app.info)) { return Zygote.MEMORY_TAG_LEVEL_TBI; } - return 0; + 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 decideGwpAsanLevel(ProcessRecord app) { @@ -1747,7 +1773,7 @@ public final class ProcessList { ? Zygote.GWP_ASAN_LEVEL_ALWAYS : Zygote.GWP_ASAN_LEVEL_NEVER; } - // Then at the applicaton attribute. + // 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 @@ -1764,6 +1790,22 @@ public final class ProcessList { return Zygote.GWP_ASAN_LEVEL_NEVER; } + private boolean enableNativeHeapZeroInit(ProcessRecord app) { + // Look at the process attribute first. + if (app.processInfo != null && app.processInfo.nativeHeapZeroInit != null) { + return app.processInfo.nativeHeapZeroInit; + } + // Then at the application attribute. + if (app.info.isNativeHeapZeroInit() != null) { + return app.info.isNativeHeapZeroInit(); + } + // 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. */ @@ -1971,6 +2013,10 @@ public final class ProcessList { runtimeFlags |= decideTaggingLevel(app); } + if (enableNativeHeapZeroInit(app)) { + runtimeFlags |= Zygote.NATIVE_HEAP_ZERO_INIT; + } + // the per-user SELinux context must be set if (TextUtils.isEmpty(app.info.seInfoUser)) { Slog.wtf(ActivityManagerService.TAG, "SELinux tag not defined", diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index c5152c081e70e..4775541c6781e 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -388,6 +388,9 @@ class ProcessRecord implements WindowProcessListener { if (processInfo.gwpAsanMode != ApplicationInfo.GWP_ASAN_DEFAULT) { pw.print(prefix); pw.println(" gwpAsanMode=" + processInfo.gwpAsanMode); } + if (processInfo.memtagMode != ApplicationInfo.MEMTAG_DEFAULT) { + pw.print(prefix); pw.println(" memtagMode=" + processInfo.memtagMode); + } } pw.print(prefix); pw.print("mRequiredAbi="); pw.print(mRequiredAbi); pw.print(" instructionSet="); pw.println(instructionSet); @@ -645,9 +648,12 @@ class ProcessRecord implements WindowProcessListener { if (processes != null) { procInfo = processes.get(_processName); if (procInfo != null && procInfo.deniedPermissions == null - && procInfo.gwpAsanMode == ApplicationInfo.GWP_ASAN_DEFAULT) { + && procInfo.gwpAsanMode == ApplicationInfo.GWP_ASAN_DEFAULT + && procInfo.memtagMode == ApplicationInfo.MEMTAG_DEFAULT + && procInfo.nativeHeapZeroInit == null) { // If this process hasn't asked for permissions to be denied, or for a - // non-default GwpAsan mode, then we don't care about it. + // non-default GwpAsan mode, or any other non-default setting, then we don't + // care about it. procInfo = null; } } diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java index 09b4f89677296..64fa708125283 100644 --- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java +++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java @@ -399,7 +399,8 @@ public class PackageInfoUtils { ParsedProcess proc = procs.get(key); retProcs.put(proc.getName(), new ProcessInfo(proc.getName(), new ArraySet<>(proc.getDeniedPermissions()), - proc.getGwpAsanMode())); + proc.getGwpAsanMode(), proc.getMemtagMode(), + proc.getNativeHeapZeroInit())); } return retProcs; }