diff options
| author | 2024-05-08 17:36:24 +0000 | |
|---|---|---|
| committer | 2024-06-04 21:43:48 +0000 | |
| commit | 3e66b0ade834fe3884712e93608f7a614b77911d (patch) | |
| tree | 82215f2209b40ca27e3b62df0963284d5b4e194d | |
| parent | b3d20839c646e92894800439120f35d66668d5b9 (diff) | |
Add new unsafe intent usage strict mode violations
Trigger unsafe intent usage violation when null action intent or
mismatching intent is being used to launch a component.
Bug: 293560872
Test: atest CtsPackageContentTestCases:SaferIntentTest
Change-Id: Ie09862a1a608b9b40f1312cf21ef66261eb479ea
16 files changed, 330 insertions, 195 deletions
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 48d9774048d0..97852528d014 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -1103,7 +1103,7 @@ public abstract class ActivityManagerInternal { /** * Trigger an unsafe intent usage strict mode violation. */ - public abstract void triggerUnsafeIntentStrictMode(int callingPid, Intent intent); + public abstract void triggerUnsafeIntentStrictMode(int callingPid, int type, Intent intent); /** * Start a foreground service delegate. diff --git a/core/java/android/app/IUnsafeIntentStrictModeCallback.aidl b/core/java/android/app/IUnsafeIntentStrictModeCallback.aidl index e2b3bb194e02..69e99a3adde7 100644 --- a/core/java/android/app/IUnsafeIntentStrictModeCallback.aidl +++ b/core/java/android/app/IUnsafeIntentStrictModeCallback.aidl @@ -24,5 +24,5 @@ import android.content.Intent; */ oneway interface IUnsafeIntentStrictModeCallback { - void onImplicitIntentMatchedInternalComponent(in Intent intent); + void onUnsafeIntent(int type, in Intent intent); } diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index 222c69ceb612..292e6bdba539 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -17,6 +17,10 @@ package android.os; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; +import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH; +import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH; +import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NULL_ACTION_MATCH; + import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; @@ -2135,27 +2139,26 @@ public final class StrictMode { } } - private static void registerIntentMatchingRestrictionCallback() { - try { - ActivityManager.getService().registerStrictModeCallback( - new UnsafeIntentStrictModeCallback()); - } catch (RemoteException e) { - /* - If exception is DeadObjectException it means system process is dead, so we can ignore - */ - if (!(e instanceof DeadObjectException)) { - Log.e(TAG, "RemoteException handling StrictMode violation", e); - } - } - } - private static final class UnsafeIntentStrictModeCallback extends IUnsafeIntentStrictModeCallback.Stub { @Override - public void onImplicitIntentMatchedInternalComponent(Intent intent) { + public void onUnsafeIntent(int type, Intent intent) { if (StrictMode.vmUnsafeIntentLaunchEnabled()) { - StrictMode.onUnsafeIntentLaunch(intent, - "Launch of unsafe implicit intent: " + intent); + StrictMode.onUnsafeIntentLaunch(type, intent); + } + } + } + + /** Each process should only have one singleton callback */ + private static volatile UnsafeIntentStrictModeCallback sUnsafeIntentCallback; + + private static void registerIntentMatchingRestrictionCallback() { + if (sUnsafeIntentCallback == null) { + sUnsafeIntentCallback = new UnsafeIntentStrictModeCallback(); + try { + ActivityManager.getService().registerStrictModeCallback(sUnsafeIntentCallback); + } catch (RemoteException e) { + // system_server should not throw } } } @@ -2383,9 +2386,22 @@ public final class StrictMode { onVmPolicyViolation(new UnsafeIntentLaunchViolation(intent)); } - /** @hide */ - public static void onUnsafeIntentLaunch(Intent intent, String message) { - onVmPolicyViolation(new UnsafeIntentLaunchViolation(intent, message)); + private static void onUnsafeIntentLaunch(int type, Intent intent) { + String msg; + switch (type) { + case UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NULL_ACTION_MATCH: + msg = "Launch of intent with null action: "; + break; + case UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH: + msg = "Implicit intent matching internal non-exported component: "; + break; + case UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH: + msg = "Intent mismatch target component intent filter: "; + break; + default: + return; + } + onVmPolicyViolation(new UnsafeIntentLaunchViolation(intent, msg + intent)); } /** Assume locked until we hear otherwise */ diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 801c7e9dce13..43774bbc51ca 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -368,17 +368,17 @@ public abstract class PackageManagerInternal { Intent intent, @Nullable String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int filterCallingUid, int userId); - /** * Retrieve all receivers that can handle a broadcast of the given intent. + * * @param filterCallingUid The results will be filtered in the context of this UID instead * of the calling UID. - * @param forSend true if the invocation is intended for sending broadcasts. The value - * of this parameter affects how packages are filtered. + * @param forSend true if the invocation is intended for sending broadcasts. The value + * of this parameter affects how packages are filtered. */ - public abstract List<ResolveInfo> queryIntentReceivers(Intent intent, - String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, - int filterCallingUid, int userId, boolean forSend); + public abstract List<ResolveInfo> queryIntentReceivers( + Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, + int filterCallingUid, int callingPid, int userId, boolean forSend); /** * Retrieve all services that can be performed for the given intent. @@ -624,6 +624,15 @@ public abstract class PackageManagerInternal { public abstract ResolveInfo resolveService(Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid); + + /** + * Resolves a service intent for start. + */ + public abstract ResolveInfo resolveService( + Intent intent, String resolvedType, + @PackageManager.ResolveInfoFlagsBits long flags, int userId, + int callingUid, int callingPid); + /** * Resolves a content provider intent. */ diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 9be0e1ff464e..8b294b3e1c75 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -4887,7 +4887,7 @@ public final class ActiveServices { } // TODO: come back and remove this assumption to triage all services ResolveInfo rInfo = mAm.getPackageManagerInternal().resolveService(service, - resolvedType, flags, userId, callingUid); + resolvedType, flags, userId, callingUid, callingPid); ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null; if (sInfo == null) { Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId + @@ -5007,7 +5007,7 @@ public final class ActiveServices { try { ResolveInfo rInfoForUserId0 = mAm.getPackageManagerInternal().resolveService(service, - resolvedType, flags, userId, callingUid); + resolvedType, flags, userId, callingUid, callingPid); if (rInfoForUserId0 == null) { Slog.w(TAG_SERVICE, "Unable to resolve service " + service + " U=" + userId diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 8a0141d08391..2600f10450eb 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5536,9 +5536,10 @@ public class ActivityManagerService extends IActivityManager.Stub packageName, UserHandle.of(userId)); String resolvedType = resolvedTypes == null || i >= resolvedTypes.length ? null : resolvedTypes[i]; - ActivityManagerUtils.logUnsafeIntentEvent( + SaferIntentUtils.reportUnsafeIntentEvent( UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NEW_MUTABLE_IMPLICIT_PENDING_INTENT_RETRIEVED, - owningUid, intent, resolvedType, isChangeEnabled); + owningUid, Process.INVALID_PID, + intent, resolvedType, isChangeEnabled); if (isChangeEnabled) { String msg = packageName + ": Targeting U+ (version " + Build.VERSION_CODES.UPSIDE_DOWN_CAKE + " and above) disallows" @@ -5798,7 +5799,7 @@ public class ActivityManagerService extends IActivityManager.Stub intent, matchFlags, uid, userId)); case ActivityManager.INTENT_SENDER_BROADCAST: return new ParceledListSlice<>(mPackageManagerInt.queryIntentReceivers( - intent, resolvedType, matchFlags, uid, userId, false)); + intent, resolvedType, matchFlags, uid, Process.INVALID_PID, userId, false)); default: // ActivityManager.INTENT_SENDER_ACTIVITY_RESULT throw new IllegalStateException("Unsupported intent sender type: " + res.key.type); } @@ -9506,14 +9507,13 @@ public class ActivityManagerService extends IActivityManager.Stub * @param callback The binder used to communicate the violations. */ @Override - public void registerStrictModeCallback(IBinder callback) { + public synchronized void registerStrictModeCallback(IBinder callback) { int callingPid = Binder.getCallingPid(); mStrictModeCallbacks.put(callingPid, IUnsafeIntentStrictModeCallback.Stub.asInterface(callback)); try { - callback.linkToDeath(new DeathRecipient() { - @Override - public void binderDied() { + callback.linkToDeath(() -> { + synchronized (ActivityManagerService.this) { mStrictModeCallbacks.remove(callingPid); } }, 0); @@ -15028,8 +15028,9 @@ public class ActivityManagerService extends IActivityManager.Stub mProcessList.sendPackageBroadcastLocked(cmd, packages, userId); } - private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType, - int callingUid, int[] users, int[] broadcastAllowList) { + private List<ResolveInfo> collectReceiverComponents( + Intent intent, String resolvedType, int callingUid, int callingPid, + int[] users, int[] broadcastAllowList) { // TODO: come back and remove this assumption to triage all broadcasts long pmFlags = STOCK_PM_FLAGS | MATCH_DEBUG_TRIAGED_MISSING; @@ -15044,7 +15045,7 @@ public class ActivityManagerService extends IActivityManager.Stub continue; } List<ResolveInfo> newReceivers = mPackageManagerInt.queryIntentReceivers( - intent, resolvedType, pmFlags, callingUid, user, true /* forSend */); + intent, resolvedType, pmFlags, callingUid, callingPid, user, /* forSend */true); if (user != UserHandle.USER_SYSTEM && newReceivers != null) { // If this is not the system user, we need to check for // any receivers that should be filtered out. @@ -15062,7 +15063,7 @@ public class ActivityManagerService extends IActivityManager.Stub final ResolveInfo ri = newReceivers.get(i); final Resolution<ResolveInfo> resolution = mComponentAliasResolver.resolveReceiver(intent, ri, resolvedType, - pmFlags, user, callingUid, true /* forSend */); + pmFlags, user, callingUid, callingPid); if (resolution == null) { // It was an alias, but the target was not found. newReceivers.remove(i); @@ -15904,6 +15905,10 @@ public class ActivityManagerService extends IActivityManager.Stub users = new int[] {userId}; } + var args = new SaferIntentUtils.IntentArgs(intent, resolvedType, + true /* isReceiver */, true /* resolveForStart */, callingUid, callingPid); + args.platformCompat = mPlatformCompat; + // Figure out who all will receive this broadcast. final int cookie = BroadcastQueue.traceBegin("queryReceivers"); List receivers = null; @@ -15911,7 +15916,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Need to resolve the intent to interested receivers... if ((intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { receivers = collectReceiverComponents( - intent, resolvedType, callingUid, users, broadcastAllowList); + intent, resolvedType, callingUid, callingPid, users, broadcastAllowList); } if (intent.getComponent() == null) { final PackageDataSnapshot snapshot = getPackageManagerInternal().snapshot(); @@ -15936,9 +15941,7 @@ public class ActivityManagerService extends IActivityManager.Stub resolvedType, false /*defaultOnly*/, userId); } if (registeredReceivers != null) { - SaferIntentUtils.blockNullAction( - mPlatformCompat, snapshot, registeredReceivers, - true, intent, callingUid); + SaferIntentUtils.blockNullAction(args, registeredReceivers); } } BroadcastQueue.traceEnd(cookie); @@ -16042,8 +16045,7 @@ public class ActivityManagerService extends IActivityManager.Stub if ((receivers != null && receivers.size() > 0) || resultTo != null) { BroadcastQueue queue = mBroadcastQueue; - SaferIntentUtils.filterNonExportedComponents(mPlatformCompat, intent, - resolvedType, receivers, callingUid, callingPid); + SaferIntentUtils.filterNonExportedComponents(args, receivers); BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType, requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions, @@ -19851,7 +19853,7 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void triggerUnsafeIntentStrictMode(int callingPid, Intent intent) { + public void triggerUnsafeIntentStrictMode(int callingPid, int type, Intent intent) { final IUnsafeIntentStrictModeCallback callback; final Intent i = intent.cloneFilter(); synchronized (ActivityManagerService.this) { @@ -19860,7 +19862,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (callback != null) { BackgroundThread.getExecutor().execute(() -> { try { - callback.onImplicitIntentMatchedInternalComponent(i); + callback.onUnsafeIntent(type, i); } catch (RemoteException e) { synchronized (ActivityManagerService.this) { mStrictModeCallbacks.remove(callingPid); diff --git a/services/core/java/com/android/server/am/ActivityManagerUtils.java b/services/core/java/com/android/server/am/ActivityManagerUtils.java index 78a2ecb8fba1..3e43a82b4abf 100644 --- a/services/core/java/com/android/server/am/ActivityManagerUtils.java +++ b/services/core/java/com/android/server/am/ActivityManagerUtils.java @@ -17,13 +17,11 @@ package com.android.server.am; import android.app.ActivityThread; import android.content.ContentResolver; -import android.content.Intent; import android.provider.Settings; import android.util.ArrayMap; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.FrameworkStatsLog; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -127,25 +125,4 @@ public class ActivityManagerUtils { return (((double) hash) / Integer.MAX_VALUE) <= rate; } - - /** - * Helper method to log an unsafe intent event. - */ - public static void logUnsafeIntentEvent(int event, int callingUid, - Intent intent, String resolvedType, boolean blocked) { - String[] categories = intent.getCategories() == null ? new String[0] - : intent.getCategories().toArray(String[]::new); - String component = intent.getComponent() == null ? null - : intent.getComponent().flattenToString(); - FrameworkStatsLog.write(FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED, - event, - callingUid, - component, - intent.getPackage(), - intent.getAction(), - categories, - resolvedType, - intent.getScheme(), - blocked); - } } diff --git a/services/core/java/com/android/server/am/ComponentAliasResolver.java b/services/core/java/com/android/server/am/ComponentAliasResolver.java index 3fa6102b64e0..5d84fd925356 100644 --- a/services/core/java/com/android/server/am/ComponentAliasResolver.java +++ b/services/core/java/com/android/server/am/ComponentAliasResolver.java @@ -455,9 +455,9 @@ public class ComponentAliasResolver { } @Nullable - public Resolution<ResolveInfo> resolveReceiver(@NonNull Intent intent, - @NonNull ResolveInfo receiver, @Nullable String resolvedType, - long packageFlags, int userId, int callingUid, boolean forSend) { + public Resolution<ResolveInfo> resolveReceiver( + @NonNull Intent intent, @NonNull ResolveInfo receiver, @Nullable String resolvedType, + long packageFlags, int userId, int callingUid, int callingPid) { // Resolve this alias. final Resolution<ComponentName> resolution = resolveComponentAlias(() -> receiver.activityInfo.getComponentName()); @@ -481,7 +481,7 @@ public class ComponentAliasResolver { i.setComponent(resolution.getTarget()); List<ResolveInfo> resolved = pmi.queryIntentReceivers( - i, resolvedType, packageFlags, callingUid, userId, forSend); + i, resolvedType, packageFlags, callingUid, callingPid, userId, /*forSend*/ true); if (resolved == null || resolved.size() == 0) { // Target component not found. Slog.w(TAG, "Alias target " + target.flattenToShortString() + " not found"); diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java index 482807c397ea..3528d3d96c2b 100644 --- a/services/core/java/com/android/server/pm/Computer.java +++ b/services/core/java/com/android/server/pm/Computer.java @@ -108,16 +108,20 @@ public interface Computer extends PackageDataSnapshot { default int getUsed() { return 0; } - @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, + @NonNull List<ResolveInfo> queryIntentActivitiesInternal( + Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, - int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits); + int filterCallingUid, int callingPid, int userId, + boolean resolveForStart, boolean allowDynamicSplits); @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, long flags, int filterCallingUid, int userId); @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, long flags, int userId); - @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, String resolvedType, - long flags, int userId, int callingUid, boolean includeInstantApps); + @NonNull List<ResolveInfo> queryIntentServicesInternal( + Intent intent, String resolvedType, long flags, + int userId, int callingUid, int callingPid, + boolean includeInstantApps, boolean resolveForStart); @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(Intent intent, String resolvedType, long flags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits, String pkgName, diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index fef22efeb158..e2a6b814cec4 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -500,10 +500,10 @@ public class ComputerEngine implements Computer { return mUsed; } - public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, - String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, + public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal( + Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, - int filterCallingUid, int userId, boolean resolveForStart, + int filterCallingUid, int callingPid, int userId, boolean resolveForStart, boolean allowDynamicSplits) { if (!mUserManager.exists(userId)) return Collections.emptyList(); @@ -530,6 +530,11 @@ public class ComputerEngine implements Computer { isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId, resolvedType, flags)); + var args = new SaferIntentUtils.IntentArgs(intent, resolvedType, + false /* isReceiver */, resolveForStart, filterCallingUid, callingPid); + args.platformCompat = mInjector.getCompatibility(); + args.snapshot = this; + List<ResolveInfo> list = Collections.emptyList(); boolean skipPostResolution = false; if (comp != null) { @@ -583,9 +588,7 @@ public class ComputerEngine implements Computer { ri.userHandle = UserHandle.of(userId); list = new ArrayList<>(1); list.add(ri); - SaferIntentUtils.enforceIntentFilterMatching( - mInjector.getCompatibility(), this, list, false, intent, - resolvedType, filterCallingUid); + SaferIntentUtils.enforceIntentFilterMatching(args, list); } } } else { @@ -609,15 +612,13 @@ public class ComputerEngine implements Computer { } list = lockedResult.result; } - SaferIntentUtils.blockNullAction( - mInjector.getCompatibility(), this, list, false, intent, filterCallingUid); + SaferIntentUtils.blockNullAction(args, list); } if (originalIntent != null) { // We also have to ensure all components match the original intent - SaferIntentUtils.enforceIntentFilterMatching( - mInjector.getCompatibility(), this, list, false, originalIntent, - resolvedType, filterCallingUid); + args.intent = originalIntent; + SaferIntentUtils.enforceIntentFilterMatching(args, list); } return skipPostResolution ? list : applyPostResolutionFilter( @@ -631,19 +632,22 @@ public class ComputerEngine implements Computer { @PackageManager.ResolveInfoFlagsBits long flags, int filterCallingUid, int userId) { return queryIntentActivitiesInternal( intent, resolvedType, flags, 0 /*privateResolveFlags*/, filterCallingUid, - userId, false /*resolveForStart*/, true /*allowDynamicSplits*/); + Process.INVALID_PID, userId, + /*resolveForStart*/ false, /*allowDynamicSplits*/ true); } public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) { return queryIntentActivitiesInternal( - intent, resolvedType, flags, 0 /*privateResolveFlags*/, Binder.getCallingUid(), - userId, false /*resolveForStart*/, true /*allowDynamicSplits*/); + intent, resolvedType, flags, 0 /*privateResolveFlags*/, + Binder.getCallingUid(), Process.INVALID_PID, userId, + /*resolveForStart*/ false, /*allowDynamicSplits*/ true); } - public final @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, - String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, - int callingUid, boolean includeInstantApps) { + public final @NonNull List<ResolveInfo> queryIntentServicesInternal( + Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, + int userId, int callingUid, int callingPid, + boolean includeInstantApps, boolean resolveForStart) { if (!mUserManager.exists(userId)) return Collections.emptyList(); enforceCrossUserOrProfilePermission(callingUid, userId, @@ -654,6 +658,11 @@ public class ComputerEngine implements Computer { flags = updateFlagsForResolve(flags, userId, callingUid, includeInstantApps, false /* isImplicitImageCaptureIntentAndNotSetByDpc */); + var args = new SaferIntentUtils.IntentArgs(intent, resolvedType, + false /* isReceiver */, resolveForStart, callingUid, callingPid); + args.platformCompat = mInjector.getCompatibility(); + args.snapshot = this; + Intent originalIntent = null; ComponentName comp = intent.getComponent(); if (comp == null) { @@ -699,23 +708,19 @@ public class ComputerEngine implements Computer { ri.serviceInfo = si; list = new ArrayList<>(1); list.add(ri); - SaferIntentUtils.enforceIntentFilterMatching( - mInjector.getCompatibility(), this, list, false, intent, - resolvedType, callingUid); + SaferIntentUtils.enforceIntentFilterMatching(args, list); } } } else { list = queryIntentServicesInternalBody(intent, resolvedType, flags, userId, callingUid, instantAppPkgName); - SaferIntentUtils.blockNullAction( - mInjector.getCompatibility(), this, list, false, intent, callingUid); + SaferIntentUtils.blockNullAction(args, list); } if (originalIntent != null) { // We also have to ensure all components match the original intent - SaferIntentUtils.enforceIntentFilterMatching( - mInjector.getCompatibility(), this, list, false, originalIntent, - resolvedType, callingUid); + args.intent = originalIntent; + SaferIntentUtils.enforceIntentFilterMatching(args, list); } return list; @@ -847,8 +852,8 @@ public class ComputerEngine implements Computer { // IMPORTANT: disallow dynamic splits to avoid an infinite loop final List<ResolveInfo> result = queryIntentActivitiesInternal( failureActivityIntent, null /*resolvedType*/, 0 /*flags*/, - 0 /*privateResolveFlags*/, filterCallingUid, userId, false /*resolveForStart*/, - false /*allowDynamicSplits*/); + 0 /*privateResolveFlags*/, filterCallingUid, Process.INVALID_PID, userId, + /*resolveForStart*/ false, /*allowDynamicSplits*/ false); final int numResults = result.size(); if (numResults > 0) { for (int i = 0; i < numResults; i++) { diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java index 0f091b04a98f..f05c54d666df 100644 --- a/services/core/java/com/android/server/pm/IPackageManagerBase.java +++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java @@ -1095,7 +1095,8 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) { final int callingUid = Binder.getCallingUid(); return new ParceledListSlice<>(snapshot().queryIntentServicesInternal( - intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/)); + intent, resolvedType, flags, userId, callingUid, Process.INVALID_PID, + /*includeInstantApps*/ false, /*resolveForStart*/ false)); } @Override @@ -1148,7 +1149,8 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { @PackageManager.ResolveInfoFlagsBits long flags, int userId) { final int callingUid = Binder.getCallingUid(); return mResolveIntentHelper.resolveServiceInternal(snapshot(), intent, - resolvedType, flags, userId, callingUid); + resolvedType, flags, userId, callingUid, Process.INVALID_PID, + /*resolveForStart*/ false); } @Override diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java index 47cb42d6d084..ed568b823159 100644 --- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java +++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java @@ -327,11 +327,11 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { @Override @Deprecated - public final List<ResolveInfo> queryIntentReceivers(Intent intent, - String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, - int filterCallingUid, int userId, boolean forSend) { + public final List<ResolveInfo> queryIntentReceivers( + Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, + int filterCallingUid, int callingPid, int userId, boolean forSend) { return getResolveIntentHelper().queryIntentReceiversInternal(snapshot(), intent, - resolvedType, flags, userId, filterCallingUid, forSend); + resolvedType, flags, userId, filterCallingUid, callingPid, forSend); } @Override @@ -341,7 +341,7 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { int userId) { final String resolvedType = intent.resolveTypeIfNeeded(getContext().getContentResolver()); return snapshot().queryIntentServicesInternal(intent, resolvedType, flags, userId, - callingUid, false); + callingUid, Process.INVALID_PID, false, /*resolveForStart*/ false); } @Override @@ -483,7 +483,18 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { public final ResolveInfo resolveService(Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid) { return getResolveIntentHelper().resolveServiceInternal(snapshot(), intent, - resolvedType, flags, userId, callingUid); + resolvedType, flags, userId, callingUid, Process.INVALID_PID, + /*resolveForStart*/ false); + } + + @Override + @Deprecated + public final ResolveInfo resolveService( + Intent intent, String resolvedType, + @PackageManager.ResolveInfoFlagsBits long flags, int userId, + int callingUid, int callingPid) { + return getResolveIntentHelper().resolveServiceInternal(snapshot(), intent, + resolvedType, flags, userId, callingUid, callingPid, /*resolveForStart*/ true); } @Override diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c40baf3e4f4a..c0fdde01652a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2810,7 +2810,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService | (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0); final Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE); List<ResolveInfo> resolvers = snapshot.queryIntentServicesInternal(resolverIntent, null, - resolveFlags, UserHandle.USER_SYSTEM, callingUid, false /*includeInstantApps*/); + resolveFlags, UserHandle.USER_SYSTEM, callingUid, Process.INVALID_PID, + /*includeInstantApps*/ false, /*resolveForStart*/ false); final int N = resolvers.size(); if (N == 0) { if (DEBUG_INSTANT) { @@ -3671,7 +3672,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, UserHandle.USER_SYSTEM, /* callingUid= */ Process.myUid(), - /* includeInstantApps= */ false); + Process.INVALID_PID, + /* includeInstantApps= */ false, + /* resolveForStart */ false); if (matches.size() == 1) { return matches.get(0).getComponentInfo().packageName; } else { diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java index a38c2dc127c4..69490a81fc86 100644 --- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java +++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java @@ -122,12 +122,14 @@ final class ResolveIntentHelper { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities"); final List<ResolveInfo> query = computer.queryIntentActivitiesInternal(intent, - resolvedType, flags, privateResolveFlags, filterCallingUid, userId, - resolveForStart, true /*allowDynamicSplits*/); + resolvedType, flags, privateResolveFlags, filterCallingUid, callingPid, + userId, resolveForStart, /*allowDynamicSplits*/ true); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - SaferIntentUtils.filterNonExportedComponents(mPlatformCompat, intent, - resolvedType, query, filterCallingUid, callingPid); + var args = new SaferIntentUtils.IntentArgs(intent, resolvedType, + false /* isReceiver */, resolveForStart, filterCallingUid, callingPid); + args.platformCompat = mPlatformCompat; + SaferIntentUtils.filterNonExportedComponents(args, query); final boolean queryMayBeFiltered = UserHandle.getAppId(filterCallingUid) >= Process.FIRST_APPLICATION_UID @@ -264,6 +266,7 @@ final class ResolveIntentHelper { throws RemoteException { Objects.requireNonNull(packageName); final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); computer.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get launch intent sender for package"); final int packageUid = computer.getPackageUid(callingPackage, 0 /* flags */, userId); @@ -279,17 +282,17 @@ final class ResolveIntentHelper { intentToResolve.setPackage(packageName); final ContentResolver contentResolver = mContext.getContentResolver(); String resolvedType = intentToResolve.resolveTypeIfNeeded(contentResolver); - List<ResolveInfo> ris = computer.queryIntentActivitiesInternal(intentToResolve, resolvedType, - 0 /* flags */, 0 /* privateResolveFlags */, callingUid, userId, - true /* resolveForStart */, false /* allowDynamicSplits */); + List<ResolveInfo> ris = computer.queryIntentActivitiesInternal(intentToResolve, + resolvedType, 0 /* flags */, 0 /* privateResolveFlags */, callingUid, callingPid, + userId, /* resolveForStart */ true, /* allowDynamicSplits */false); if (ris == null || ris.size() <= 0) { intentToResolve.removeCategory(Intent.CATEGORY_INFO); intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER); intentToResolve.setPackage(packageName); resolvedType = intentToResolve.resolveTypeIfNeeded(contentResolver); ris = computer.queryIntentActivitiesInternal(intentToResolve, resolvedType, - 0 /* flags */, 0 /* privateResolveFlags */, callingUid, userId, - true /* resolveForStart */, false /* allowDynamicSplits */); + 0 /* flags */, 0 /* privateResolveFlags */, callingUid, callingPid, + userId, /* resolveForStart */ true, /* allowDynamicSplits */false); } final Intent intent = new Intent(intentToResolve); @@ -323,16 +326,17 @@ final class ResolveIntentHelper { String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, int queryingUid) { return queryIntentReceiversInternal(computer, intent, resolvedType, flags, userId, - queryingUid, false); + queryingUid, Process.INVALID_PID, false); } /** - * @see PackageManagerInternal#queryIntentReceivers(Intent, String, long, int, int, boolean) + * @see PackageManagerInternal#queryIntentReceivers */ @NonNull - public List<ResolveInfo> queryIntentReceiversInternal(Computer computer, Intent intent, - String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, - int filterCallingUid, boolean forSend) { + public List<ResolveInfo> queryIntentReceiversInternal( + Computer computer, Intent intent, String resolvedType, + @PackageManager.ResolveInfoFlagsBits long flags, int userId, + int filterCallingUid, int callingPid, boolean forSend) { if (!mUserManager.exists(userId)) return Collections.emptyList(); // The identity used to filter the receiver components final int queryingUid = forSend ? Process.SYSTEM_UID : filterCallingUid; @@ -354,6 +358,12 @@ final class ResolveIntentHelper { } final ComponentResolverApi componentResolver = computer.getComponentResolver(); List<ResolveInfo> list = Collections.emptyList(); + + var args = new SaferIntentUtils.IntentArgs(intent, resolvedType, + true /* isReceiver */, forSend, filterCallingUid, callingPid); + args.platformCompat = mPlatformCompat; + args.snapshot = computer; + if (comp != null) { final ActivityInfo ai = computer.getReceiverInfo(comp, flags, userId); if (ai != null) { @@ -390,9 +400,7 @@ final class ResolveIntentHelper { ri.activityInfo = ai; list = new ArrayList<>(1); list.add(ri); - SaferIntentUtils.enforceIntentFilterMatching( - mPlatformCompat, computer, list, true, intent, - resolvedType, filterCallingUid); + SaferIntentUtils.enforceIntentFilterMatching(args, list); } } } else { @@ -412,15 +420,13 @@ final class ResolveIntentHelper { list = result; } } - SaferIntentUtils.blockNullAction( - mPlatformCompat, computer, list, true, intent, filterCallingUid); + SaferIntentUtils.blockNullAction(args, list); } if (originalIntent != null) { // We also have to ensure all components match the original intent - SaferIntentUtils.enforceIntentFilterMatching( - mPlatformCompat, computer, - list, true, originalIntent, resolvedType, filterCallingUid); + args.intent = originalIntent; + SaferIntentUtils.enforceIntentFilterMatching(args, list); } return computer.applyPostResolutionFilter(list, instantAppPkgName, false, queryingUid, @@ -428,14 +434,16 @@ final class ResolveIntentHelper { } - public ResolveInfo resolveServiceInternal(@NonNull Computer computer, Intent intent, + public ResolveInfo resolveServiceInternal( + @NonNull Computer computer, Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, - int callingUid) { + int callingUid, int callingPid, boolean resolveForStart) { if (!mUserManager.exists(userId)) return null; flags = computer.updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/, false /* isImplicitImageCaptureIntentAndNotSetByDpc */); List<ResolveInfo> query = computer.queryIntentServicesInternal( - intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/); + intent, resolvedType, flags, userId, callingUid, callingPid, + /*includeInstantApps*/ false, resolveForStart); if (query != null) { if (query.size() >= 1) { // If there is more than one service with the same priority, diff --git a/services/core/java/com/android/server/pm/SaferIntentUtils.java b/services/core/java/com/android/server/pm/SaferIntentUtils.java index 8b6ac9f7569c..8175321ea293 100644 --- a/services/core/java/com/android/server/pm/SaferIntentUtils.java +++ b/services/core/java/com/android/server/pm/SaferIntentUtils.java @@ -36,6 +36,7 @@ import android.content.pm.ComponentInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Build; +import android.os.Process; import android.os.UserHandle; import android.security.Flags; import android.util.Log; @@ -44,9 +45,9 @@ import android.util.Printer; import android.util.Slog; import com.android.internal.pm.pkg.component.ParsedMainComponent; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.IntentResolver; import com.android.server.LocalServices; -import com.android.server.am.ActivityManagerUtils; import com.android.server.am.BroadcastFilter; import com.android.server.compat.PlatformCompat; import com.android.server.pm.resolution.ComponentResolverApi; @@ -54,6 +55,21 @@ import com.android.server.pm.snapshot.PackageDataSnapshot; import java.util.List; +/** + * The way Safer Intent is implemented is to add several "hooks" into PMS's intent + * resolution process, and in some cases, AMS's runtime receiver resolution. Think of + * these methods as resolution "passes", where they post-process the resolved component list. + * <p> + * Here are the 4 main hooking entry points for each component type: + * <ul> + * <li>Activity: {@link ComputerEngine#queryIntentActivitiesInternal} or + * {@link ResolveIntentHelper#resolveIntentInternal}</li> + * <li>Service: {@link Computer#queryIntentServicesInternal}</li> + * <li>Static BroadcastReceivers: {@link ResolveIntentHelper#queryIntentReceiversInternal}</li> + * <li>Runtime BroadcastReceivers: + * {@link com.android.server.am.ActivityManagerService#broadcastIntentLockedTraced}</li> + * </ul> + */ public class SaferIntentUtils { // This is a hack to workaround b/240373119; a proper fix should be implemented instead. @@ -63,7 +79,7 @@ public class SaferIntentUtils { /** * Apps targeting Android U and above will need to export components in order to invoke them * through implicit intents. - * + * <p> * If a component is not exported and invoked, it will be removed from the list of receivers. * This applies specifically to activities and broadcasts. */ @@ -76,7 +92,7 @@ public class SaferIntentUtils { * Intents sent from apps enabling this feature will stop resolving to components with * non matching intent filters, even when explicitly setting a component name, unless the * target components are in the same app as the calling app. - * + * <p> * When an app registers an exported component in its manifest and adds <intent-filter>s, * the component can be started by any intent - even those that do not match the intent filter. * This has proven to be something that many developers find counterintuitive. @@ -105,22 +121,103 @@ public class SaferIntentUtils { } /** - * Under the correct conditions, remove components if the intent has null action. - * + * Helper method to report an unsafe intent event. + */ + public static void reportUnsafeIntentEvent( + int event, int callingUid, int callingPid, + Intent intent, String resolvedType, boolean blocked) { + String[] categories = intent.getCategories() == null ? new String[0] + : intent.getCategories().toArray(String[]::new); + String component = intent.getComponent() == null ? null + : intent.getComponent().flattenToString(); + FrameworkStatsLog.write(FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED, + event, + callingUid, + component, + intent.getPackage(), + intent.getAction(), + categories, + resolvedType, + intent.getScheme(), + blocked); + LocalServices.getService(ActivityManagerInternal.class) + .triggerUnsafeIntentStrictMode(callingPid, event, intent); + } + + /** + * All the relevant information about an intent resolution transaction. + */ + public static class IntentArgs { + + /* Several system_server components */ + + @Nullable + public PlatformCompat platformCompat; + @Nullable + public PackageDataSnapshot snapshot; + + /* Information about the intent itself */ + + public Intent intent; + public String resolvedType; + public boolean isReceiver; + + /* Information about the caller */ + + // Whether this intent resolution transaction is actually for starting a component and + // not only for querying matching components. + // This information is required because we only want to log and trigger strict mode + // violations on unsafe intent events when the caller actually wants to start something. + public boolean resolveForStart; + public int callingUid; + // When resolveForStart is false, callingPid does not matter as this is only used + // to lookup the strict mode violation callback. + public int callingPid; + + public IntentArgs( + Intent intent, String resolvedType, boolean isReceiver, + boolean resolveForStart, int callingUid, int callingPid) { + this.isReceiver = isReceiver; + this.intent = intent; + this.resolvedType = resolvedType; + this.resolveForStart = resolveForStart; + this.callingUid = callingUid; + this.callingPid = resolveForStart ? callingPid : Process.INVALID_PID; + } + + boolean isChangeEnabled(long changeId) { + return platformCompat == null || platformCompat.isChangeEnabledByUidInternal( + changeId, callingUid); + } + + void reportEvent(int event, boolean blocked) { + if (resolveForStart) { + SaferIntentUtils.reportUnsafeIntentEvent( + event, callingUid, callingPid, intent, resolvedType, blocked); + } + } + } + + /** + * Remove components if the intent has null action. + * <p> + * Because blocking null action applies to all resolution cases, it has to be hooked + * in all 4 locations. Note, for component intent resolution in Activity, Service, + * and static BroadcastReceivers, null action blocking is actually handled within + * {@link #enforceIntentFilterMatching}; we only need to handle it in this method when + * the intent does not specify an explicit component name. + * <p> * `compat` and `snapshot` may be null when this method is called in ActivityManagerService - * CTS tests. The code in this method will properly avoid control flows using these arguments. + * CTS tests. The code in this method shall properly avoid control flows using these arguments. */ - public static void blockNullAction( - @Nullable PlatformCompat compat, @Nullable PackageDataSnapshot snapshot, - List componentList, boolean isReceiver, Intent intent, int filterCallingUid) { - if (ActivityManager.canAccessUnexportedComponents(filterCallingUid)) return; + public static void blockNullAction(IntentArgs args, List componentList) { + if (ActivityManager.canAccessUnexportedComponents(args.callingUid)) return; - final Computer computer = (Computer) snapshot; + final Computer computer = (Computer) args.snapshot; ComponentResolverApi resolver = null; final boolean enforce = Flags.blockNullActionIntents() - && (compat == null || compat.isChangeEnabledByUidInternal( - IntentFilter.BLOCK_NULL_ACTION_INTENTS, filterCallingUid)); + && args.isChangeEnabled(IntentFilter.BLOCK_NULL_ACTION_INTENTS); for (int i = componentList.size() - 1; i >= 0; --i) { boolean match = true; @@ -135,22 +232,21 @@ public class SaferIntentUtils { resolver = computer.getComponentResolver(); } final ParsedMainComponent comp = infoToComponent( - resolveInfo.getComponentInfo(), resolver, isReceiver); - if (!comp.getIntents().isEmpty() && intent.getAction() == null) { + resolveInfo.getComponentInfo(), resolver, args.isReceiver); + if (!comp.getIntents().isEmpty() && args.intent.getAction() == null) { match = false; } } else if (c instanceof IntentFilter) { - if (intent.getAction() == null) { + if (args.intent.getAction() == null) { match = false; } } if (!match) { - ActivityManagerUtils.logUnsafeIntentEvent( - UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NULL_ACTION_MATCH, - filterCallingUid, intent, null, enforce); + args.reportEvent( + UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NULL_ACTION_MATCH, enforce); if (enforce) { - Slog.w(TAG, "Blocking intent with null action: " + intent); + Slog.w(TAG, "Blocking intent with null action: " + args.intent); componentList.remove(i); } } @@ -158,18 +254,21 @@ public class SaferIntentUtils { } /** - * Remove ResolveInfos that does not match the provided intent. + * Remove ResolveInfos that does not match the provided component intent. + * <p> + * Component intents cannot refer to a runtime registered BroadcastReceiver, so we only + * need to hook into the rest of the 3 entry points. Please note, this method also + * handles null action blocking for all component intents; do not go through an additional + * {@link #blockNullAction} pass! */ public static void enforceIntentFilterMatching( - PlatformCompat compat, PackageDataSnapshot snapshot, - List<ResolveInfo> resolveInfos, boolean isReceiver, - Intent intent, String resolvedType, int filterCallingUid) { + IntentArgs args, List<ResolveInfo> resolveInfos) { if (DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS.get()) return; // Do not enforce filter matching when the caller is system or root - if (ActivityManager.canAccessUnexportedComponents(filterCallingUid)) return; + if (ActivityManager.canAccessUnexportedComponents(args.callingUid)) return; - final Computer computer = (Computer) snapshot; + final Computer computer = (Computer) args.snapshot; final ComponentResolverApi resolver = computer.getComponentResolver(); final Printer logPrinter = DEBUG_INTENT_MATCHING @@ -177,21 +276,19 @@ public class SaferIntentUtils { : null; final boolean enforceMatch = Flags.enforceIntentFilterMatch() - && compat.isChangeEnabledByUidInternal( - ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS, filterCallingUid); + && args.isChangeEnabled(ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS); final boolean blockNullAction = Flags.blockNullActionIntents() - && compat.isChangeEnabledByUidInternal( - IntentFilter.BLOCK_NULL_ACTION_INTENTS, filterCallingUid); + && args.isChangeEnabled(IntentFilter.BLOCK_NULL_ACTION_INTENTS); for (int i = resolveInfos.size() - 1; i >= 0; --i) { final ComponentInfo info = resolveInfos.get(i).getComponentInfo(); // Skip filter matching when the caller is targeting the same app - if (UserHandle.isSameApp(filterCallingUid, info.applicationInfo.uid)) { + if (UserHandle.isSameApp(args.callingUid, info.applicationInfo.uid)) { continue; } - final ParsedMainComponent comp = infoToComponent(info, resolver, isReceiver); + final ParsedMainComponent comp = infoToComponent(info, resolver, args.isReceiver); if (comp == null || comp.getIntents().isEmpty()) { continue; @@ -199,10 +296,10 @@ public class SaferIntentUtils { Boolean match = null; - if (intent.getAction() == null) { - ActivityManagerUtils.logUnsafeIntentEvent( + if (args.intent.getAction() == null) { + args.reportEvent( UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NULL_ACTION_MATCH, - filterCallingUid, intent, resolvedType, enforceMatch && blockNullAction); + enforceMatch && blockNullAction); if (blockNullAction) { // Skip intent filter matching if blocking null action match = false; @@ -213,7 +310,8 @@ public class SaferIntentUtils { // Check if any intent filter matches for (int j = 0, size = comp.getIntents().size(); j < size; ++j) { IntentFilter intentFilter = comp.getIntents().get(j).getIntentFilter(); - if (IntentResolver.intentMatchesFilter(intentFilter, intent, resolvedType)) { + if (IntentResolver.intentMatchesFilter( + intentFilter, args.intent, args.resolvedType)) { match = true; break; } @@ -226,19 +324,19 @@ public class SaferIntentUtils { // true : The intent matches at least one intent filter if (match == null) { - ActivityManagerUtils.logUnsafeIntentEvent( + args.reportEvent( UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH, - filterCallingUid, intent, resolvedType, enforceMatch); + enforceMatch); match = false; } if (!match) { // All non-matching intents has to be marked accordingly if (Flags.enforceIntentFilterMatch()) { - intent.addExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH); + args.intent.addExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH); } if (enforceMatch) { - Slog.w(TAG, "Intent does not match component's intent filter: " + intent); + Slog.w(TAG, "Intent does not match component's intent filter: " + args.intent); Slog.w(TAG, "Access blocked: " + comp.getComponentName()); if (DEBUG_INTENT_MATCHING) { Slog.v(TAG, "Component intent filters:"); @@ -253,19 +351,21 @@ public class SaferIntentUtils { /** * Filter non-exported components from the componentList if intent is implicit. + * <p> + * Implicit intents cannot be used to start Services since API 21+. + * Implicit broadcasts cannot be delivered to static BroadcastReceivers since API 25+. + * So we only need to hook into Activity and runtime BroadcastReceiver intent resolution. */ - public static void filterNonExportedComponents( - PlatformCompat platformCompat, Intent intent, String resolvedType, List componentList, - int callingUid, int callingPid) { + public static void filterNonExportedComponents(IntentArgs args, List componentList) { if (componentList == null - || intent.getPackage() != null - || intent.getComponent() != null - || ActivityManager.canAccessUnexportedComponents(callingUid)) { + || args.intent.getPackage() != null + || args.intent.getComponent() != null + || ActivityManager.canAccessUnexportedComponents(args.callingUid)) { return; } - final boolean enforce = platformCompat.isChangeEnabledByUidInternal( - IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS, callingUid); + final boolean enforce = + args.isChangeEnabled(IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS); boolean violated = false; for (int i = componentList.size() - 1; i >= 0; i--) { @@ -289,11 +389,9 @@ public class SaferIntentUtils { } if (violated) { - ActivityManagerUtils.logUnsafeIntentEvent( + args.reportEvent( UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH, - callingUid, intent, resolvedType, enforce); - LocalServices.getService(ActivityManagerInternal.class) - .triggerUnsafeIntentStrictMode(callingPid, intent); + enforce); } } } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java index daa827eacf44..5f126774835d 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java @@ -556,7 +556,7 @@ public final class ServiceBindingOomAdjPolicyTest { rInfo.serviceInfo = makeServiceInfo(compName.getClassName(), compName.getPackageName(), serviceUid); doReturn(rInfo).when(mPackageManagerInt).resolveService(any(Intent.class), any(), - anyLong(), anyInt(), anyInt()); + anyLong(), anyInt(), anyInt(), anyInt()); return serviceIntent; } |