From 102d3d86691ca7cb23e27ee964d1b45e6aa5b784 Mon Sep 17 00:00:00 2001 From: Evgenii Stepanov Date: Wed, 12 Feb 2020 16:48:14 -0800 Subject: [PATCH] Add "enableGwpAsan" tag to android manifest. This tag can be used to enable and disable gwp-asan on applications and their components. The default setting is disabled, except for the system applications which are enabled with a small probability (approx. 1% of processes). Enabling gwp-asan can be used to crowd test an app. This change includes a compat feature that overrides the default value of enableGwpAsan for an app. Bug: 149991821 Test: atest CtsGwpAsanTestCases Exempt-From-Owner-Approval: cherrypick Merged-In: I5eb647c517e5487b1d1eed6b9a43242490f19289 Change-Id: I5b4db666f38af846927f88702cc690f0916cadb1 --- api/current.txt | 2 + .../android/content/pm/ApplicationInfo.java | 26 ++- core/java/android/content/pm/ProcessInfo.java | 153 ++++++++++++++---- .../content/pm/parsing/ParsingPackage.java | 2 + .../pm/parsing/ParsingPackageImpl.java | 21 ++- .../pm/parsing/ParsingPackageRead.java | 7 + .../pm/parsing/ParsingPackageUtils.java | 6 + .../pm/parsing/component/ParsedProcess.java | 23 ++- .../parsing/component/ParsedProcessUtils.java | 5 + core/java/com/android/internal/os/Zygote.java | 27 ++++ .../com/android/internal/util/Parcelling.java | 27 ++++ core/jni/com_android_internal_os_Zygote.cpp | 24 ++- .../android/content/package_item_info.proto | 1 + core/res/res/values/attrs_manifest.xml | 26 +++ core/res/res/values/public.xml | 1 + .../com/android/server/am/ProcessList.java | 34 ++++ .../com/android/server/am/ProcessRecord.java | 3 + .../server/pm/parsing/PackageInfoUtils.java | 5 +- 18 files changed, 351 insertions(+), 42 deletions(-) diff --git a/api/current.txt b/api/current.txt index 4e203dd7c0f71..d813fe083bcee 100644 --- a/api/current.txt +++ b/api/current.txt @@ -572,6 +572,7 @@ package android { field public static final int elevation = 16843840; // 0x1010440 field public static final int ellipsize = 16842923; // 0x10100ab field public static final int ems = 16843096; // 0x1010158 + field public static final int enableGwpAsan = 16844310; // 0x1010616 field public static final int enableVrMode = 16844069; // 0x1010525 field public static final int enabled = 16842766; // 0x101000e field public static final int end = 16843996; // 0x10104dc @@ -11439,6 +11440,7 @@ package android.content.pm { method public int describeContents(); method public void dump(android.util.Printer, String); method public static CharSequence getCategoryTitle(android.content.Context, int); + method @Nullable public Boolean isGwpAsanEnabled(); method public boolean isProfileableByShell(); method public boolean isResourceOverlay(); method public boolean isVirtualPreload(); diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index a15afe04201b0..c82fffa4aa006 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -25,6 +25,7 @@ import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ProcessInfo; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Build; @@ -38,6 +39,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,7 +59,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 @@ -1272,6 +1276,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { /** @hide */ public String zygotePreloadName; + /** + * Indicates if the application has requested GWP-ASan to be enabled, disabled, or left + * unspecified. Processes can override this setting. + * @hide + */ + @Nullable + public Boolean enableGwpAsan; + /** * Represents the default policy. The actual policy used will depend on other properties of * the application, e.g. the target SDK version. @@ -1413,6 +1425,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { pw.println(prefix + "usesNonSdkApi=" + usesNonSdkApi()); pw.println(prefix + "allowsPlaybackCapture=" + (isAudioPlaybackCaptureAllowed() ? "true" : "false")); + if (enableGwpAsan != null) { + pw.println(prefix + "enableGwpAsan=" + enableGwpAsan); + } } super.dumpBack(pw, prefix); } @@ -1511,6 +1526,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { if (category != CATEGORY_UNDEFINED) { proto.write(ApplicationInfoProto.Detail.CATEGORY, category); } + if (enableGwpAsan != null) { + proto.write(ApplicationInfoProto.Detail.ENABLE_GWP_ASAN, enableGwpAsan); + } proto.end(detailToken); } proto.end(token); @@ -1620,6 +1638,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { mHiddenApiPolicy = orig.mHiddenApiPolicy; hiddenUntilInstalled = orig.hiddenUntilInstalled; zygotePreloadName = orig.zygotePreloadName; + enableGwpAsan = orig.enableGwpAsan; } public String toString() { @@ -1703,6 +1722,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeInt(mHiddenApiPolicy); dest.writeInt(hiddenUntilInstalled ? 1 : 0); dest.writeString(zygotePreloadName); + sForBoolean.parcel(enableGwpAsan, dest, parcelableFlags); } public static final @android.annotation.NonNull Parcelable.Creator CREATOR @@ -1783,6 +1803,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { mHiddenApiPolicy = source.readInt(); hiddenUntilInstalled = source.readInt() != 0; zygotePreloadName = source.readString(); + enableGwpAsan = sForBoolean.unparcel(source); } /** @@ -2161,6 +2182,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { /** {@hide} */ public void setResourcePath(String resourcePath) { scanPublicSourceDir = resourcePath; } /** {@hide} */ public void setBaseResourcePath(String baseResourcePath) { publicSourceDir = baseResourcePath; } /** {@hide} */ public void setSplitResourcePaths(String[] splitResourcePaths) { splitPublicSourceDirs = splitResourcePaths; } + /** {@hide} */ public void setGwpAsanEnabled(@Nullable Boolean value) { enableGwpAsan = value; } /** {@hide} */ @UnsupportedAppUsage @@ -2172,4 +2194,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { @UnsupportedAppUsage public String getBaseResourcePath() { return publicSourceDir; } /** {@hide} */ public String[] getSplitResourcePaths() { return splitPublicSourceDirs; } + @Nullable + public Boolean isGwpAsanEnabled() { return enableGwpAsan; } } diff --git a/core/java/android/content/pm/ProcessInfo.java b/core/java/android/content/pm/ProcessInfo.java index c77a267958f59..a3730672b9881 100644 --- a/core/java/android/content/pm/ProcessInfo.java +++ b/core/java/android/content/pm/ProcessInfo.java @@ -23,66 +23,157 @@ import android.os.Parcelable; import android.text.TextUtils; import android.util.ArraySet; +import com.android.internal.util.DataClass; +import com.android.internal.util.Parcelling; + /** * Information about a process an app may run. This corresponds to information collected from the * AndroidManifest.xml's <permission-group> tags. * @hide */ +@DataClass(genGetters = true, genSetters = false, genParcelable = true, genAidl = false, + genBuilder = false) public class ProcessInfo implements Parcelable { /** * The name of the process, fully-qualified based on the app's package name. */ + @NonNull public String name; /** * If non-null, these are permissions that are not allowed in this process. */ @Nullable + @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringArraySet.class) public ArraySet deniedPermissions; - public ProcessInfo(String name, ArraySet deniedPermissions) { - this.name = name; - this.deniedPermissions = deniedPermissions; - } + /** + * Indicates if the process has requested GWP-ASan to be enabled, disabled, or left unspecified. + */ + @Nullable + public Boolean enableGwpAsan; @Deprecated public ProcessInfo(@NonNull ProcessInfo orig) { this.name = orig.name; this.deniedPermissions = orig.deniedPermissions; + this.enableGwpAsan = orig.enableGwpAsan; } - public int describeContents() { - return 0; + + + // Code below generated by codegen v1.0.15. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/ProcessInfo.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Creates a new ProcessInfo. + * + * @param name + * The name of the process, fully-qualified based on the app's package name. + * @param deniedPermissions + * If non-null, these are permissions that are not allowed in this process. + * @param enableGwpAsan + * Indicates if the process has requested GWP-ASan to be enabled, disabled, or left unspecified. + */ + @DataClass.Generated.Member + public ProcessInfo( + @NonNull String name, + @Nullable ArraySet deniedPermissions, + @Nullable Boolean enableGwpAsan) { + this.name = name; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, name); + this.deniedPermissions = deniedPermissions; + this.enableGwpAsan = enableGwpAsan; + + // onConstructed(); // You can define this method to get a callback } - public void writeToParcel(Parcel dest, int parcelableFlags) { - dest.writeString(this.name); - final int numDenied = this.deniedPermissions != null - ? this.deniedPermissions.size() : 0; - dest.writeInt(numDenied); - for (int i = 0; i < numDenied; i++) { - dest.writeString(this.deniedPermissions.valueAt(i)); + @DataClass.Generated.Member + static Parcelling> sParcellingForDeniedPermissions = + Parcelling.Cache.get( + Parcelling.BuiltIn.ForInternedStringArraySet.class); + static { + if (sParcellingForDeniedPermissions == null) { + sParcellingForDeniedPermissions = Parcelling.Cache.put( + new Parcelling.BuiltIn.ForInternedStringArraySet()); } } - public static final @NonNull Creator CREATOR = - new Creator() { - public ProcessInfo createFromParcel(Parcel source) { - return new ProcessInfo(source); - } - public ProcessInfo[] newArray(int size) { - return new ProcessInfo[size]; - } - }; + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } - private ProcessInfo(Parcel source) { - this.name = source.readString(); - final int numDenied = source.readInt(); - if (numDenied > 0) { - this.deniedPermissions = new ArraySet<>(numDenied); - for (int i = numDenied - 1; i >= 0; i--) { - this.deniedPermissions.add(TextUtils.safeIntern(source.readString())); - } - } + byte flg = 0; + if (deniedPermissions != null) flg |= 0x2; + if (enableGwpAsan != null) flg |= 0x4; + dest.writeByte(flg); + dest.writeString(name); + sParcellingForDeniedPermissions.parcel(deniedPermissions, dest, flags); + if (enableGwpAsan != null) dest.writeBoolean(enableGwpAsan); } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected ProcessInfo(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + byte flg = in.readByte(); + String _name = in.readString(); + ArraySet _deniedPermissions = sParcellingForDeniedPermissions.unparcel(in); + Boolean _enableGwpAsan = (flg & 0x4) == 0 ? null : (Boolean) in.readBoolean(); + + this.name = _name; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, name); + this.deniedPermissions = _deniedPermissions; + this.enableGwpAsan = _enableGwpAsan; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public ProcessInfo[] newArray(int size) { + return new ProcessInfo[size]; + } + + @Override + public ProcessInfo createFromParcel(@NonNull Parcel in) { + return new ProcessInfo(in); + } + }; + + @DataClass.Generated( + time = 1582840056156L, + codegenVersion = "1.0.15", + 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.annotation.Nullable java.lang.Boolean enableGwpAsan\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() {} + + + //@formatter:on + // End of generated code + } diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java index aa93d80fbfeb0..a479b2e5b4d10 100644 --- a/core/java/android/content/pm/parsing/ParsingPackage.java +++ b/core/java/android/content/pm/parsing/ParsingPackage.java @@ -236,6 +236,8 @@ public interface ParsingPackage extends ParsingPackageRead { ParsingPackage setEnabled(boolean enabled); + ParsingPackage setGwpAsanEnabled(Boolean enableGwpAsan); + 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 a9b72d041f8b2..f6a415e5dc55d 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java +++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java @@ -30,6 +30,7 @@ import android.content.pm.FeatureGroupInfo; import android.content.pm.FeatureInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageParser; +import android.content.pm.ProcessInfo; import android.content.pm.parsing.component.ParsedActivity; import android.content.pm.parsing.component.ParsedComponent; import android.content.pm.parsing.component.ParsedFeature; @@ -406,6 +407,10 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { private boolean allowNativeHeapPointerTagging; private boolean preserveLegacyExternalStorage; + @Nullable + @DataClass.ParcelWith(ForBoolean.class) + protected Boolean enableGwpAsan = null; + // TODO(chiuwinson): Non-null @Nullable private ArraySet mimeGroups; @@ -904,7 +909,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { appInfo.volumeUuid = volumeUuid; appInfo.zygotePreloadName = zygotePreloadName; appInfo.crossProfile = isCrossProfile(); - + appInfo.setGwpAsanEnabled(enableGwpAsan); appInfo.setBaseCodePath(baseCodePath); appInfo.setBaseResourcePath(baseCodePath); appInfo.setCodePath(codePath); @@ -1086,6 +1091,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { dest.writeBoolean(this.allowNativeHeapPointerTagging); dest.writeBoolean(this.preserveLegacyExternalStorage); dest.writeArraySet(this.mimeGroups); + sForBoolean.parcel(this.enableGwpAsan, dest, flags); } public ParsingPackageImpl(Parcel in) { @@ -1243,6 +1249,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { this.allowNativeHeapPointerTagging = in.readBoolean(); this.preserveLegacyExternalStorage = in.readBoolean(); this.mimeGroups = (ArraySet) in.readArraySet(boot); + this.enableGwpAsan = sForBoolean.unparcel(in); } public static final Parcelable.Creator CREATOR = @@ -1964,6 +1971,12 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { return directBootAware; } + @Override + @Nullable + public Boolean isGwpAsanEnabled() { + return enableGwpAsan; + } + @Override public boolean isPartiallyDirectBootAware() { return partiallyDirectBootAware; @@ -2419,6 +2432,12 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { return this; } + @Override + public ParsingPackageImpl setGwpAsanEnabled(@Nullable Boolean value) { + enableGwpAsan = 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 048b924e10ccb..61d7824c2cde5 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageRead.java +++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java @@ -840,6 +840,13 @@ public interface ParsingPackageRead extends Parcelable { @Nullable Set getMimeGroups(); + /** + * @see ApplicationInfo#enableGwpAsan + * @see R.styleable#AndroidManifest_enableGwpAsan + */ + @Nullable + public Boolean isGwpAsanEnabled(); + // 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 b4f21593165fa..19da71c19737d 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -40,6 +40,7 @@ import android.content.pm.ConfigurationInfo; import android.content.pm.FeatureGroupInfo; import android.content.pm.FeatureInfo; import android.content.pm.PackageInfo; +import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; @@ -1660,6 +1661,11 @@ public class ParsingPackageUtils { && !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) { return input.error("Invalid class loader name: " + classLoaderName); } + + if (sa.hasValue(R.styleable.AndroidManifestApplication_enableGwpAsan)) { + pkg.setGwpAsanEnabled( + sa.getBoolean(R.styleable.AndroidManifestApplication_enableGwpAsan, 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 da7bf984aa7f0..3b6020a72469b 100644 --- a/core/java/android/content/pm/parsing/component/ParsedProcess.java +++ b/core/java/android/content/pm/parsing/component/ParsedProcess.java @@ -41,6 +41,9 @@ public class ParsedProcess implements Parcelable { @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class) protected Set deniedPermissions = emptySet(); + @Nullable + protected Boolean enableGwpAsan = null; + public ParsedProcess() { } @@ -71,13 +74,15 @@ public class ParsedProcess implements Parcelable { @DataClass.Generated.Member public ParsedProcess( @NonNull String name, - @NonNull Set deniedPermissions) { + @NonNull Set deniedPermissions, + @Nullable Boolean enableGwpAsan) { this.name = name; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, name); this.deniedPermissions = deniedPermissions; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, deniedPermissions); + this.enableGwpAsan = enableGwpAsan; // onConstructed(); // You can define this method to get a callback } @@ -92,6 +97,11 @@ public class ParsedProcess implements Parcelable { return deniedPermissions; } + @DataClass.Generated.Member + public @Nullable Boolean getEnableGwpAsan() { + return enableGwpAsan; + } + @DataClass.Generated.Member static Parcelling> sParcellingForDeniedPermissions = Parcelling.Cache.get( @@ -109,8 +119,12 @@ public class ParsedProcess implements Parcelable { // You can override field parcelling by defining methods like: // void parcelFieldName(Parcel dest, int flags) { ... } + byte flg = 0; + if (enableGwpAsan != null) flg |= 0x4; + dest.writeByte(flg); dest.writeString(name); sParcellingForDeniedPermissions.parcel(deniedPermissions, dest, flags); + if (enableGwpAsan != null) dest.writeBoolean(enableGwpAsan); } @Override @@ -124,8 +138,10 @@ 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); + Boolean _enableGwpAsan = (flg & 0x4) == 0 ? null : (Boolean) in.readBoolean(); this.name = _name; com.android.internal.util.AnnotationValidations.validate( @@ -133,6 +149,7 @@ public class ParsedProcess implements Parcelable { this.deniedPermissions = _deniedPermissions; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, deniedPermissions); + this.enableGwpAsan = _enableGwpAsan; // onConstructed(); // You can define this method to get a callback } @@ -152,10 +169,10 @@ public class ParsedProcess implements Parcelable { }; @DataClass.Generated( - time = 1581452315946L, + time = 1582589960479L, codegenVersion = "1.0.14", 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\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 @android.annotation.Nullable java.lang.Boolean enableGwpAsan\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 48250666a58b9..3820790cc2b17 100644 --- a/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java +++ b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java @@ -103,6 +103,11 @@ public class ParsedProcessUtils { if (proc.name == null || proc.name.length() <= 0) { return input.error(" does not specify android:process"); } + + if (sa.hasValue(R.styleable.AndroidManifestProcess_enableGwpAsan)) { + proc.enableGwpAsan = + sa.getBoolean(R.styleable.AndroidManifestProcess_enableGwpAsan, 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 94924a57e3f23..633aa2c5ffb42 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -140,6 +140,33 @@ public final class Zygote { */ public static final int MEMORY_TAG_LEVEL_SYNC = 3 << 19; + /** + * A two-bit field for GWP-ASan level of this process. See the possible values below. + */ + public static final int GWP_ASAN_LEVEL_MASK = (1 << 21) | (1 << 22); + + /** + * Disable GWP-ASan in this process. + * GWP-ASan is a low-overhead memory bug detector using guard pages on a small + * subset of heap allocations. + */ + public static final int GWP_ASAN_LEVEL_NEVER = 0 << 21; + + /** + * Enable GWP-ASan in this process with a small sampling rate. + * With approx. 1% chance GWP-ASan will be activated and apply its protection + * to a small subset of heap allocations. + * Otherwise (~99% chance) this process is unaffected. + */ + public static final int GWP_ASAN_LEVEL_LOTTERY = 1 << 21; + + /** + * Always enable GWP-ASan in this process. + * GWP-ASan is activated unconditionally (but still, only a small subset of + * allocations is protected). + */ + public static final int GWP_ASAN_LEVEL_ALWAYS = 2 << 21; + /** 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/java/com/android/internal/util/Parcelling.java b/core/java/com/android/internal/util/Parcelling.java index 7f567b948eb2f..dd64c402fdbf4 100644 --- a/core/java/com/android/internal/util/Parcelling.java +++ b/core/java/com/android/internal/util/Parcelling.java @@ -221,6 +221,33 @@ public interface Parcelling { } } + class ForInternedStringArraySet implements Parcelling> { + @Override + public void parcel(ArraySet item, Parcel dest, int parcelFlags) { + if (item == null) { + dest.writeInt(-1); + } else { + dest.writeInt(item.size()); + for (String string : item) { + dest.writeString(string); + } + } + } + + @Override + public ArraySet unparcel(Parcel source) { + final int size = source.readInt(); + if (size < 0) { + return null; + } + ArraySet set = new ArraySet<>(); + for (int count = 0; count < size; count++) { + set.add(TextUtils.safeIntern(source.readString())); + } + return set; + } + } + class ForBoolean implements Parcelling { @Override public void parcel(@Nullable Boolean item, Parcel dest, int parcelFlags) { diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 2128f99ff609d..f9885e2909c25 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -356,10 +356,14 @@ static const std::array ExternalStorage // Must match values in com.android.internal.os.Zygote. enum RuntimeFlags : uint32_t { - DEBUG_ENABLE_JDWP = 1, - PROFILE_FROM_SHELL = 1 << 15, - MEMORY_TAG_LEVEL_MASK = (1 << 19) | (1 << 20), - MEMORY_TAG_LEVEL_TBI = 1 << 19, + DEBUG_ENABLE_JDWP = 1, + PROFILE_FROM_SHELL = 1 << 15, + MEMORY_TAG_LEVEL_MASK = (1 << 19) | (1 << 20), + MEMORY_TAG_LEVEL_TBI = 1 << 19, + GWP_ASAN_LEVEL_MASK = (1 << 21) | (1 << 22), + GWP_ASAN_LEVEL_NEVER = 0 << 21, + GWP_ASAN_LEVEL_LOTTERY = 1 << 21, + GWP_ASAN_LEVEL_ALWAYS = 2 << 21, }; enum UnsolicitedZygoteMessageTypes : uint32_t { @@ -1741,6 +1745,18 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, } android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &heap_tagging_level, sizeof(heap_tagging_level)); + bool forceEnableGwpAsan = false; + switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) { + default: + case RuntimeFlags::GWP_ASAN_LEVEL_NEVER: + break; + case RuntimeFlags::GWP_ASAN_LEVEL_ALWAYS: + forceEnableGwpAsan = true; + [[fallthrough]]; + case RuntimeFlags::GWP_ASAN_LEVEL_LOTTERY: + android_mallopt(M_INITIALIZE_GWP_ASAN, &forceEnableGwpAsan, sizeof(forceEnableGwpAsan)); + } + if (NeedsNoRandomizeWorkaround()) { // Work around ARM kernel ASLR lossage (http://b/5817320). int old_personality = personality(0xffffffff); diff --git a/core/proto/android/content/package_item_info.proto b/core/proto/android/content/package_item_info.proto index 4a7d04361a5b0..e8ae1b3c9dc5a 100644 --- a/core/proto/android/content/package_item_info.proto +++ b/core/proto/android/content/package_item_info.proto @@ -109,6 +109,7 @@ message ApplicationInfoProto { } optional int32 network_security_config_res = 17; optional int32 category = 18; + optional bool enable_gwp_asan = 19; } optional Detail detail = 17; } diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index c2451319bdc8c..ba939eaa638ad 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1541,6 +1541,28 @@ + + + + + +