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

Commit 3d7c3b68 authored by John Wu's avatar John Wu Committed by Android (Google) Code Review
Browse files

Merge "Block intents with action set as null" into udc-dev

parents 305d693b a6904f89
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -556,7 +556,12 @@ public class ApplicationPackageManager extends PackageManager {
    @Override
    public ActivityInfo getActivityInfo(ComponentName className, ComponentInfoFlags flags)
            throws NameNotFoundException {
        final int userId = getUserId();
        return getActivityInfoAsUser(className, flags, getUserId());
    }

    @Override
    public ActivityInfo getActivityInfoAsUser(ComponentName className,
            ComponentInfoFlags flags, @UserIdInt int userId) throws NameNotFoundException {
        try {
            ActivityInfo ai = mPM.getActivityInfo(className,
                    updateFlagsForComponent(flags.getValue(), userId, null), userId);
+31 −2
Original line number Diff line number Diff line
@@ -20,6 +20,9 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.Uri;
import android.os.Build;
@@ -181,6 +184,28 @@ public class IntentFilter implements Parcelable {
    private static final String[] EMPTY_STRING_ARRAY = new String[0];
    private static final boolean[] EMPTY_BOOLEAN_ARRAY = new boolean[0];

    /**
     * An intent with action set as null used to always pass the action test during intent
     * filter matching. This causes a lot of confusion and unexpected intent matches.
     * Null action intents should be blocked when either the intent sender or receiver
     * application targets U or higher.
     *
     * mBlockNullAction indicates whether the intent filter owner (intent receiver) is
     * targeting U+. This value will be properly set by package manager when IntentFilters are
     * passed to an application, so that when an application is trying to perform intent filter
     * matching locally, the correct matching algorithm will be chosen.
     *
     * When an IntentFilter is sent to system server (e.g. for registering runtime receivers),
     * the value set in mBlockNullAction will be ignored and overwritten with the correct
     * value evaluated based on the Binder calling identity. This makes sure that the
     * security enforcement cannot be bypassed by crafting a malicious IntentFilter.
     *
     * @hide
     */
    @ChangeId
    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
    public static final long BLOCK_NULL_ACTION_INTENTS = 264497795;

    /**
     * The filter {@link #setPriority} value at which system high-priority
     * receivers are placed; that is, receivers that should execute before
@@ -2276,6 +2301,7 @@ public class IntentFilter implements Parcelable {
        String type = resolve ? intent.resolveType(resolver) : intent.getType();
        return match(intent.getAction(), type, intent.getScheme(),
                     intent.getData(), intent.getCategories(), logTag,
                     CompatChanges.isChangeEnabled(BLOCK_NULL_ACTION_INTENTS),
                     false /* supportWildcards */, null /* ignoreActions */,
                     intent.getExtras());
    }
@@ -2328,6 +2354,7 @@ public class IntentFilter implements Parcelable {
            Uri data, Set<String> categories, String logTag, boolean supportWildcards,
            @Nullable Collection<String> ignoreActions) {
        return match(action, type, scheme, data, categories, logTag, supportWildcards,
                CompatChanges.isChangeEnabled(BLOCK_NULL_ACTION_INTENTS),
                ignoreActions, null /* extras */);
    }

@@ -2339,8 +2366,10 @@ public class IntentFilter implements Parcelable {
     */
    public final int match(String action, String type, String scheme,
            Uri data, Set<String> categories, String logTag, boolean supportWildcards,
            @Nullable Collection<String> ignoreActions, @Nullable Bundle extras) {
        if (action != null && !matchAction(action, supportWildcards, ignoreActions)) {
            boolean blockNullAction, @Nullable Collection<String> ignoreActions,
            @Nullable Bundle extras) {
        if ((action == null && blockNullAction)
                || !matchAction(action, supportWildcards, ignoreActions)) {
            if (false) Log.v(
                logTag, "No matching action " + action + " for " + this);
            return NO_MATCH_ACTION;
+11 −0
Original line number Diff line number Diff line
@@ -5719,6 +5719,17 @@ public abstract class PackageManager {
                "getActivityInfo not implemented in subclass");
    }

    /**
     * @hide
     */
    @NonNull
    public ActivityInfo getActivityInfoAsUser(@NonNull ComponentName component,
            @NonNull ComponentInfoFlags flags, @UserIdInt int userId)
            throws NameNotFoundException {
        throw new UnsupportedOperationException(
                "getActivityInfoAsUser not implemented in subclass");
    }

    /**
     * Retrieve all of the information we know about a particular receiver
     * class.
+52 −12
Original line number Diff line number Diff line
@@ -16,12 +16,18 @@

package com.android.server;

import static android.content.IntentFilter.BLOCK_NULL_ACTION_INTENTS;

import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NULL_ACTION_MATCH;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Binder;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.FastImmutableArraySet;
@@ -34,6 +40,7 @@ import android.util.Slog;
import android.util.proto.ProtoOutputStream;

import com.android.internal.util.FastPrintWriter;
import com.android.server.am.ActivityManagerUtils;
import com.android.server.pm.Computer;
import com.android.server.pm.snapshot.PackageDataSnapshot;

@@ -81,7 +88,7 @@ public abstract class IntentResolver<F, R extends Object> {
     * Returns whether an intent matches the IntentFilter with a pre-resolved type.
     */
    public static boolean intentMatchesFilter(
            IntentFilter filter, Intent intent, String resolvedType) {
            IntentFilter filter, Intent intent, String resolvedType, boolean blockNullAction) {
        final boolean debug = localLOGV
                || ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);

@@ -95,7 +102,8 @@ public abstract class IntentResolver<F, R extends Object> {
        }

        final int match = filter.match(intent.getAction(), resolvedType, intent.getScheme(),
                intent.getData(), intent.getCategories(), TAG);
                intent.getData(), intent.getCategories(), TAG, /* supportWildcards */ false,
                blockNullAction, null, null);

        if (match >= 0) {
            if (debug) {
@@ -350,14 +358,32 @@ public abstract class IntentResolver<F, R extends Object> {
        return Collections.unmodifiableSet(mFilters);
    }

    private boolean blockNullAction(Computer computer, Intent intent,
            String resolvedType, int callingUid, boolean debug) {
        if (intent.getAction() == null) {
            final boolean blockNullAction = UserHandle.isCore(callingUid)
                    || computer.isChangeEnabled(BLOCK_NULL_ACTION_INTENTS, callingUid);
            ActivityManagerUtils.logUnsafeIntentEvent(
                    UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NULL_ACTION_MATCH,
                    callingUid, intent, resolvedType, blockNullAction);
            if (blockNullAction) {
                if (debug) Slog.v(TAG, "Skip matching filters: action is null");
                return true;
            }
        }
        return false;
    }

    public List<R> queryIntentFromList(@NonNull Computer computer, Intent intent,
            String resolvedType, boolean defaultOnly, ArrayList<F[]> listCut, int userId,
            long customFlags) {
            String resolvedType, boolean defaultOnly, ArrayList<F[]> listCut,
            int callingUid, @UserIdInt int userId, long customFlags) {
        ArrayList<R> resultList = new ArrayList<R>();

        final boolean debug = localLOGV ||
                ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);

        if (blockNullAction(computer, intent, resolvedType, callingUid, debug)) return resultList;

        FastImmutableArraySet<String> categories = getFastIntentCategories(intent);
        final String scheme = intent.getScheme();
        int N = listCut.size();
@@ -365,18 +391,26 @@ public abstract class IntentResolver<F, R extends Object> {
            buildResolveList(computer, intent, categories, debug, defaultOnly, resolvedType, scheme,
                    listCut.get(i), resultList, userId, customFlags);
        }
        filterResults(resultList);
        filterResults(computer, intent, resultList);
        sortResults(resultList);
        return resultList;
    }

    public List<R> queryIntent(@NonNull PackageDataSnapshot snapshot, Intent intent,
    public final List<R> queryIntent(@NonNull PackageDataSnapshot snapshot, Intent intent,
            String resolvedType, boolean defaultOnly, @UserIdInt int userId) {
        return queryIntent(snapshot, intent, resolvedType, defaultOnly, userId, 0);
        return queryIntent(snapshot, intent, resolvedType, defaultOnly,
                Binder.getCallingUid(), userId, 0);
    }

    public List<R> queryIntent(@NonNull PackageDataSnapshot snapshot, Intent intent,
            String resolvedType, boolean defaultOnly, int callingUid, @UserIdInt int userId) {
        return queryIntent(snapshot, intent, resolvedType, defaultOnly, callingUid, userId, 0);
    }

    protected final List<R> queryIntent(@NonNull PackageDataSnapshot snapshot, Intent intent,
            String resolvedType, boolean defaultOnly, @UserIdInt int userId, long customFlags) {
            String resolvedType, boolean defaultOnly, int callingUid, @UserIdInt int userId,
            long customFlags) {
        final Computer computer = (Computer) snapshot;
        String scheme = intent.getScheme();

        ArrayList<R> finalList = new ArrayList<R>();
@@ -388,6 +422,8 @@ public abstract class IntentResolver<F, R extends Object> {
            TAG, "Resolving type=" + resolvedType + " scheme=" + scheme
            + " defaultOnly=" + defaultOnly + " userId=" + userId + " of " + intent);

        if (blockNullAction(computer, intent, resolvedType, callingUid, debug)) return finalList;

        F[] firstTypeCut = null;
        F[] secondTypeCut = null;
        F[] thirdTypeCut = null;
@@ -448,7 +484,6 @@ public abstract class IntentResolver<F, R extends Object> {
        }

        FastImmutableArraySet<String> categories = getFastIntentCategories(intent);
        Computer computer = (Computer) snapshot;
        if (firstTypeCut != null) {
            buildResolveList(computer, intent, categories, debug, defaultOnly, resolvedType,
                    scheme, firstTypeCut, finalList, userId, customFlags);
@@ -465,7 +500,7 @@ public abstract class IntentResolver<F, R extends Object> {
            buildResolveList(computer, intent, categories, debug, defaultOnly, resolvedType,
                    scheme, schemeCut, finalList, userId, customFlags);
        }
        filterResults(finalList);
        filterResults(computer, intent, finalList);
        sortResults(finalList);

        if (debug) {
@@ -534,7 +569,8 @@ public abstract class IntentResolver<F, R extends Object> {
    /**
     * Apply filtering to the results. This happens before the results are sorted.
     */
    protected void filterResults(List<R> results) {
    protected void filterResults(@NonNull Computer computer, @NonNull Intent intent,
            List<R> results) {
    }

    protected void dumpFilter(PrintWriter out, String prefix, F filter) {
@@ -766,7 +802,11 @@ public abstract class IntentResolver<F, R extends Object> {
                continue;
            }

            match = intentFilter.match(action, resolvedType, scheme, data, categories, TAG);
            match = intentFilter.match(action, resolvedType, scheme, data, categories, TAG,
                    false /*supportWildcards*/,
                    false /*blockNullAction: already handled*/,
                    null /*ignoreActions*/,
                    null /*extras*/);
            if (match >= 0) {
                if (debug) Slog.v(TAG, "  Filter matched!  match=0x" +
                        Integer.toHexString(match) + " hasDefault="
+24 −3
Original line number Diff line number Diff line
@@ -1126,6 +1126,19 @@ public class ActivityManagerService extends IActivityManager.Stub
            return null;
        }
        @Override
        protected void filterResults(@NonNull Computer computer,
                @NonNull Intent intent, List<BroadcastFilter> results) {
            if (intent.getAction() != null) return;
            // When the resolved component is targeting U+, block null action intents
            for (int i = results.size() - 1; i >= 0; --i) {
                if (computer.isChangeEnabled(
                        IntentFilter.BLOCK_NULL_ACTION_INTENTS, results.get(i).owningUid)) {
                    results.remove(i);
                }
            }
        }
        @Override
        protected IntentFilter getIntentFilter(@NonNull BroadcastFilter input) {
            return input;
@@ -13939,11 +13952,19 @@ public class ActivityManagerService extends IActivityManager.Stub
                        (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                    continue;
                }
                final boolean blockNullAction = mPlatformCompat.isChangeEnabledInternal(
                        IntentFilter.BLOCK_NULL_ACTION_INTENTS, callerApp.info);
                // If intent has scheme "content", it will need to access
                // provider that needs to lock mProviderMap in ActivityThread
                // and also it may need to wait application response, so we
                // cannot lock ActivityManagerService here.
                if (filter.match(resolver, intent, true, TAG) >= 0) {
                if (filter.match(intent.getAction(), intent.resolveType(resolver),
                        intent.getScheme(), intent.getData(), intent.getCategories(), TAG,
                        false /* supportWildcards */,
                        blockNullAction,
                        null /* ignoreActions */,
                        intent.getExtras()) >= 0) {
                    if (allSticky == null) {
                        allSticky = new ArrayList<Intent>();
                    }
@@ -14962,7 +14983,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                    }
                    List<BroadcastFilter> registeredReceiversForUser =
                            mReceiverResolver.queryIntent(snapshot, intent,
                                    resolvedType, false /*defaultOnly*/, users[i]);
                                    resolvedType, false /*defaultOnly*/, callingUid, users[i]);
                    if (registeredReceivers == null) {
                        registeredReceivers = registeredReceiversForUser;
                    } else if (registeredReceiversForUser != null) {
@@ -14971,7 +14992,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                }
            } else {
                registeredReceivers = mReceiverResolver.queryIntent(snapshot, intent,
                        resolvedType, false /*defaultOnly*/, userId);
                        resolvedType, false /*defaultOnly*/, callingUid, userId);
            }
        }
        BroadcastQueue.traceEnd(cookie);
Loading