From fb92f4386aef904d778feb65ce10e333ebe97413 Mon Sep 17 00:00:00 2001 From: Azhara Assanova Date: Tue, 17 Jan 2023 17:07:52 +0000 Subject: [PATCH] Define FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT for PendingIntent Starting from target SDK U, we want to block creation of mutable PendingIntents with implicit Intents because attackers can mutate the Intent object within and launch altered behavior on behalf of victim apps. For more details on the vulnerability, see go/pendingintent-rca. This change is planned to be part of the Safer Intents and Components feature b/229362273. ag/20580416 is the initial CL that introduced this feature. This change defines FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT that allows to bypass the newly introduced block for cases when an implicit intent is required. Testing and the actual block will happen in a subsequent CL after we finish migrating platform code to use safer PendingIntents. For now, there is a Slog.wtfStack() that acts as a warning about the upcoming change. Bug: 236704164 Bug: 229362273 Test: atest PendingIntentTest CTS-Coverage-Bug: 266434003 Change-Id: I701f7e3ab3e95deb5b8b6990c5d67b7d66a052b0 --- core/api/current.txt | 1 + core/java/android/app/PendingIntent.java | 29 ++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index 4b1335e0d6d60..e02b6796f08d8 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -6725,6 +6725,7 @@ package android.app { method public static void writePendingIntentOrNullToParcel(@Nullable android.app.PendingIntent, @NonNull android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; + field public static final int FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT = 16777216; // 0x1000000 field public static final int FLAG_CANCEL_CURRENT = 268435456; // 0x10000000 field public static final int FLAG_IMMUTABLE = 67108864; // 0x4000000 field public static final int FLAG_MUTABLE = 33554432; // 0x2000000 diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index c58e627425b7d..dd4453114fe52 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -186,6 +186,7 @@ public final class PendingIntent implements Parcelable { FLAG_IMMUTABLE, FLAG_MUTABLE, FLAG_MUTABLE_UNAUDITED, + FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT, Intent.FILL_IN_ACTION, Intent.FILL_IN_DATA, @@ -279,6 +280,21 @@ public final class PendingIntent implements Parcelable { @TestApi public static final int FLAG_MUTABLE_UNAUDITED = FLAG_MUTABLE; + /** + * Flag indicating that the created PendingIntent with {@link #FLAG_MUTABLE} + * is allowed to have an unsafe implicit Intent within.

Starting with + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, for apps that + * target SDK {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or + * higher, creation of a PendingIntent with {@link #FLAG_MUTABLE} and an + * implicit Intent within will throw an {@link IllegalArgumentException} + * for security reasons. To bypass this check, use + * {@link #FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT} when creating a PendingIntent. + * However, it is strongly recommended to not to use this flag and make the + * Intent explicit or the PendingIntent immutable, thereby making the Intent + * safe. + */ + public static final int FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT = 1<<24; + /** * Exception thrown when trying to send through a PendingIntent that * has been canceled or is otherwise no longer able to execute the request. @@ -418,12 +434,13 @@ public final class PendingIntent implements Parcelable { // This will be changed to a throw of an exception on the server side once we finish // migrating to safer PendingIntents b/262253127. // - Otherwise, warn that it will be blocked from target SDK U. - if (isNewMutableImplicitPendingIntent(flags, intent)) { + if (isNewMutableDisallowedImplicitPendingIntent(flags, intent)) { if (Compatibility.isChangeEnabled(BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT)) { String msg = packageName + ": Targeting U+ (version " + Build.VERSION_CODES.UPSIDE_DOWN_CAKE + " and above) disallows" + " creating or retrieving a PendingIntent with FLAG_MUTABLE," - + " an implicit Intent within and without FLAG_NO_CREATE for" + + " an implicit Intent within and without FLAG_NO_CREATE and" + + " FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT for" + " security reasons. To retrieve an already existing" + " PendingIntent, use FLAG_NO_CREATE, however, to create a" + " new PendingIntent with an implicit Intent use" @@ -441,11 +458,15 @@ public final class PendingIntent implements Parcelable { } /** @hide */ - public static boolean isNewMutableImplicitPendingIntent(int flags, @NonNull Intent intent) { + public static boolean isNewMutableDisallowedImplicitPendingIntent(int flags, + @NonNull Intent intent) { boolean isFlagNoCreateSet = (flags & PendingIntent.FLAG_NO_CREATE) != 0; boolean isFlagMutableSet = (flags & PendingIntent.FLAG_MUTABLE) != 0; boolean isImplicit = (intent.getComponent() == null) && (intent.getPackage() == null); - return !isFlagNoCreateSet && isFlagMutableSet && isImplicit; + boolean isFlagAllowUnsafeImplicitIntentSet = + (flags & PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT) != 0; + return !isFlagNoCreateSet && isFlagMutableSet && isImplicit + && !isFlagAllowUnsafeImplicitIntentSet; } /**