Merge "Revert^2 "Verify that the component is exported""

This commit is contained in:
Christophe Pinelli
2022-09-16 15:00:46 +00:00
committed by Android (Google) Code Review
7 changed files with 155 additions and 2 deletions

View File

@@ -4216,13 +4216,23 @@ public class ActivityManager {
}
}*/
/** @hide
* Determines whether the given UID can access unexported components
* @param uid the calling UID
* @return true if the calling UID is ROOT or SYSTEM
*/
public static boolean canAccessUnexportedComponents(int uid) {
final int appId = UserHandle.getAppId(uid);
return (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID);
}
/** @hide */
@UnsupportedAppUsage
public static int checkComponentPermission(String permission, int uid,
int owningUid, boolean exported) {
// Root, system server get to do everything.
final int appId = UserHandle.getAppId(uid);
if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
if (canAccessUnexportedComponents(uid)) {
return PackageManager.PERMISSION_GRANTED;
}
// Isolated processes don't get any permissions.

View File

@@ -576,6 +576,14 @@ public abstract class PackageManagerInternal {
@PrivateResolveFlags long privateResolveFlags, int userId, boolean resolveForStart,
int filterCallingUid);
/**
* Resolves an exported activity intent, allowing instant apps to be resolved.
*/
public abstract ResolveInfo resolveIntentExported(Intent intent, String resolvedType,
@PackageManager.ResolveInfoFlagsBits long flags,
@PrivateResolveFlags long privateResolveFlags, int userId, boolean resolveForStart,
int filterCallingUid);
/**
* Resolves a service intent, allowing instant apps to be resolved.
*/

View File

@@ -215,6 +215,7 @@ import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetManagerInternal;
import android.compat.annotation.ChangeId;
import android.compat.annotation.Disabled;
import android.compat.annotation.EnabledAfter;
import android.content.AttributionSource;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
@@ -584,6 +585,17 @@ public class ActivityManagerService extends IActivityManager.Stub
@Disabled
private static final long DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED = 161145287L;
/**
* Apps targeting Android U and above will need to export components in order to invoke them
* through implicit intents.
*
* If a component is not exported and invoked, it will be removed from the list of receivers.
* This applies specifically to activities and broadcasts.
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
public static final long IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS = 229362273;
/**
* The maximum number of bytes that {@link #setProcessStateSummary} accepts.
*
@@ -12378,6 +12390,58 @@ public class ActivityManagerService extends IActivityManager.Stub
return false;
}
/**
* Filters out non-exported components in a given list of broadcast filters
* @param intent the original intent
* @param callingUid the calling UID
* @param query the list of broadcast filters
* @param platformCompat the instance of platform compat
*/
private static void filterNonExportedComponents(Intent intent, int callingUid,
List query, PlatformCompat platformCompat, String callerPackage) {
if (query == null
|| intent.getPackage() != null
|| intent.getComponent() != null
|| ActivityManager.canAccessUnexportedComponents(callingUid)) {
return;
}
for (int i = query.size() - 1; i >= 0; i--) {
String componentInfo;
ResolveInfo resolveInfo;
BroadcastFilter broadcastFilter;
if (query.get(i) instanceof ResolveInfo) {
resolveInfo = (ResolveInfo) query.get(i);
if (resolveInfo.getComponentInfo().exported) {
continue;
}
componentInfo = resolveInfo.getComponentInfo()
.getComponentName().flattenToShortString();
} else if (query.get(i) instanceof BroadcastFilter) {
broadcastFilter = (BroadcastFilter) query.get(i);
if (broadcastFilter.exported) {
continue;
}
componentInfo = broadcastFilter.packageName;
} else {
continue;
}
if (!platformCompat.isChangeEnabledByUid(
IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS, callingUid)) {
Slog.w(TAG, "Non-exported component not filtered out "
+ "(will be filtered out once the app targets U+)- intent: "
+ intent.getAction() + ", component: "
+ componentInfo + ", sender: "
+ callerPackage);
return;
}
Slog.w(TAG, "Non-exported component filtered out - intent: "
+ intent.getAction() + ", component: "
+ componentInfo + ", sender: "
+ callerPackage);
query.remove(i);
}
}
/**
* Main code for cleaning up a process when it has gone away. This is
* called both as a result of the process dying, or directly when stopping
@@ -14217,6 +14281,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
filterNonExportedComponents(intent, callingUid, registeredReceivers,
mPlatformCompat, callerPackage);
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) {
// If we are not serializing this broadcast, then send the
@@ -14319,6 +14385,8 @@ public class ActivityManagerService extends IActivityManager.Stub
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) {
BroadcastQueue queue = broadcastQueueForIntent(intent);
filterNonExportedComponents(intent, callingUid, receivers,
mPlatformCompat, callerPackage);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,

View File

@@ -465,6 +465,20 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
filterCallingUid);
}
/**
* @deprecated similar to {@link resolveIntent} but limits the matches to exported components.
*/
@Override
@Deprecated
public final ResolveInfo resolveIntentExported(Intent intent, String resolvedType,
@PackageManager.ResolveInfoFlagsBits long flags,
@PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
boolean resolveForStart, int filterCallingUid) {
return getResolveIntentHelper().resolveIntentInternal(snapshot(),
intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart,
filterCallingUid, true);
}
@Override
@Deprecated
public final ResolveInfo resolveService(Intent intent, String resolvedType,

View File

@@ -52,6 +52,7 @@ import android.util.Slog;
import com.android.internal.app.ResolverActivity;
import com.android.internal.util.ArrayUtils;
import com.android.server.am.ActivityManagerService;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
@@ -100,6 +101,38 @@ final class ResolveIntentHelper {
mInstantAppInstallerActivitySupplier = instantAppInstallerActivitySupplier;
}
private static void filterNonExportedComponents(Intent intent, int filterCallingUid,
List<ResolveInfo> query, PlatformCompat platformCompat, Computer computer) {
if (query == null
|| intent.getPackage() != null
|| intent.getComponent() != null
|| ActivityManager.canAccessUnexportedComponents(filterCallingUid)) {
return;
}
AndroidPackage caller = computer.getPackage(filterCallingUid);
String callerPackage = caller == null ? "Not specified" : caller.getPackageName();
for (int i = query.size() - 1; i >= 0; i--) {
if (!query.get(i).getComponentInfo().exported) {
if (!platformCompat.isChangeEnabledByUid(
ActivityManagerService.IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS,
filterCallingUid)) {
Slog.w(TAG, "Non-exported component not filtered out "
+ "(will be filtered out once the app targets U+)- intent: "
+ intent.getAction() + ", component: "
+ query.get(i).getComponentInfo()
.getComponentName().flattenToShortString()
+ ", starter: " + callerPackage);
return;
}
Slog.w(TAG, "Non-exported component filtered out - intent: "
+ intent.getAction() + ", component: "
+ query.get(i).getComponentInfo().getComponentName().flattenToShortString()
+ ", starter: " + callerPackage);
query.remove(i);
}
}
}
/**
* Normally instant apps can only be resolved when they're visible to the caller.
* However, if {@code resolveForStart} is {@code true}, all instant apps are visible
@@ -109,6 +142,20 @@ final class ResolveIntentHelper {
@PackageManager.ResolveInfoFlagsBits long flags,
@PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
boolean resolveForStart, int filterCallingUid) {
return resolveIntentInternal(computer, intent, resolvedType, flags,
privateResolveFlags, userId, resolveForStart, filterCallingUid, false);
}
/**
* Normally instant apps can only be resolved when they're visible to the caller.
* However, if {@code resolveForStart} is {@code true}, all instant apps are visible
* since we need to allow the system to start any installed application.
* Allows picking exported components only.
*/
public ResolveInfo resolveIntentInternal(Computer computer, Intent intent, String resolvedType,
@PackageManager.ResolveInfoFlagsBits long flags,
@PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
boolean resolveForStart, int filterCallingUid, boolean exportedComponentsOnly) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
@@ -124,6 +171,10 @@ final class ResolveIntentHelper {
final List<ResolveInfo> query = computer.queryIntentActivitiesInternal(intent,
resolvedType, flags, privateResolveFlags, filterCallingUid, userId,
resolveForStart, true /*allowDynamicSplits*/);
if (exportedComponentsOnly) {
filterNonExportedComponents(intent, filterCallingUid, query,
mPlatformCompat, computer);
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
final boolean queryMayBeFiltered =

View File

@@ -744,7 +744,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
// (e.g. AMS.startActivityAsUser).
final long token = Binder.clearCallingIdentity();
try {
return mService.getPackageManagerInternalLocked().resolveIntent(
return mService.getPackageManagerInternalLocked().resolveIntentExported(
intent, resolvedType, modifiedFlags, privateResolveFlags, userId, true,
filterCallingUid);
} finally {

View File

@@ -379,6 +379,8 @@ public class ActivityStarterTests extends WindowTestsBase {
doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any());
doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyLong(), anyLong(),
anyInt(), anyBoolean(), anyInt());
doReturn(null).when(mMockPackageManager).resolveIntentExported(any(), any(),
anyLong(), anyLong(), anyInt(), anyBoolean(), anyInt());
doReturn(new ComponentName("", "")).when(mMockPackageManager).getSystemUiServiceComponent();
// Never review permissions