Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d474f51 authored by Azhara Assanova's avatar Azhara Assanova
Browse files

Add WW logging to block mutable implicit PendingIntent

To implement WW logging, this change moves the IllegalArgumentException
throw from the client side to the server side.

Bug: 266584933
Test: atest PendingIntentTest
Test: statsd_testdrive 573
Change-Id: I17dbbbbebdc75d160af3ddfd341c414cc7e03b24
parent d3b56789
Loading
Loading
Loading
Loading
+12 −24
Original line number Diff line number Diff line
@@ -428,30 +428,18 @@ public final class PendingIntent implements Parcelable {
                throw new IllegalArgumentException(msg);
        }

        // Whenever creation or retrieval of a mutable implicit PendingIntent occurs:
        // - For apps with target SDK >= U, throw an IllegalArgumentException for
        //   security reasons.
        // - Otherwise, warn that it will be blocked from target SDK U onwards.
        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 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"
                        + " FLAG_IMMUTABLE.";
                throw new IllegalArgumentException(msg);
            } else {
        // For apps with target SDK < U, warn that creation or retrieval of a mutable
        // implicit PendingIntent will be blocked from target SDK U onwards for security
        // reasons. The block itself happens on the server side, but this warning has to
        // stay here to preserve the client side stack trace for app developers.
        if (isNewMutableDisallowedImplicitPendingIntent(flags, intent)
                && !Compatibility.isChangeEnabled(BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT)) {
            String msg = "New mutable implicit PendingIntent: pkg=" + packageName
                    + ", action=" + intent.getAction()
                    + ", featureId=" + context.getAttributionTag()
                    + ". This will be blocked once the app targets U+"
                    + " for security reasons.";
                Log.w(TAG, new RuntimeException(msg));
            }
            Log.w(TAG, new StackTrace(msg));
        }
    }

+40 −1
Original line number Diff line number Diff line
@@ -101,6 +101,8 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED;
import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NEW_MUTABLE_IMPLICIT_PENDING_INTENT_RETRIEVED;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALLOWLISTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
@@ -5509,6 +5511,25 @@ public class ActivityManagerService extends IActivityManager.Stub
                        throw new IllegalArgumentException(
                                "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
                    }
                    if (PendingIntent.isNewMutableDisallowedImplicitPendingIntent(flags, intent)) {
                        boolean isChangeEnabled = CompatChanges.isChangeEnabled(
                                        PendingIntent.BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT,
                                        owningUid);
                        logUnsafeMutableImplicitPi(packageName, resolvedTypes, owningUid, i, intent,
                                isChangeEnabled);
                        if (isChangeEnabled) {
                            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 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"
                                    + " FLAG_IMMUTABLE.";
                            throw new IllegalArgumentException(msg);
                        }
                    }
                    intents[i] = new Intent(intent);
                }
            }
@@ -5561,6 +5582,24 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
    }
    private void logUnsafeMutableImplicitPi(String packageName, String[] resolvedTypes,
            int owningUid, int i, Intent intent, boolean isChangeEnabled) {
        String[] categories = intent.getCategories() == null ? new String[0]
                : intent.getCategories().toArray(String[]::new);
        String resolvedType = resolvedTypes == null || i >= resolvedTypes.length ? null
                : resolvedTypes[i];
        FrameworkStatsLog.write(UNSAFE_INTENT_EVENT_REPORTED,
                UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NEW_MUTABLE_IMPLICIT_PENDING_INTENT_RETRIEVED,
                owningUid,
                null,
                packageName,
                intent.getAction(),
                categories,
                resolvedType,
                intent.getScheme(),
                isChangeEnabled);
    }
    @Override
    public int sendIntentSender(IApplicationThread caller, IIntentSender target,
            IBinder allowlistToken, int code, Intent intent, String resolvedType,
@@ -12716,7 +12755,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                    callingUid);
            String[] categories = intent.getCategories() == null ? new String[0]
                    : intent.getCategories().toArray(String[]::new);
            FrameworkStatsLog.write(FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED,
            FrameworkStatsLog.write(UNSAFE_INTENT_EVENT_REPORTED,
                    FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH,
                    callingUid,
                    componentInfo,