summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author John Wu <topjohnwu@google.com> 2024-05-08 17:36:24 +0000
committer John Wu <topjohnwu@google.com> 2024-06-04 21:43:48 +0000
commit3e66b0ade834fe3884712e93608f7a614b77911d (patch)
tree82215f2209b40ca27e3b62df0963284d5b4e194d
parentb3d20839c646e92894800439120f35d66668d5b9 (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
-rw-r--r--core/java/android/app/ActivityManagerInternal.java2
-rw-r--r--core/java/android/app/IUnsafeIntentStrictModeCallback.aidl2
-rw-r--r--core/java/android/os/StrictMode.java56
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java21
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java4
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java40
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerUtils.java23
-rw-r--r--services/core/java/com/android/server/am/ComponentAliasResolver.java8
-rw-r--r--services/core/java/com/android/server/pm/Computer.java12
-rw-r--r--services/core/java/com/android/server/pm/ComputerEngine.java59
-rw-r--r--services/core/java/com/android/server/pm/IPackageManagerBase.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerInternalBase.java23
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java7
-rw-r--r--services/core/java/com/android/server/pm/ResolveIntentHelper.java58
-rw-r--r--services/core/java/com/android/server/pm/SaferIntentUtils.java202
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java2
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 &lt;intent-filter&gt;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;
}