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

Commit 51b3aacc authored by Todd Kennedy's avatar Todd Kennedy
Browse files

Implement service filtering

Instant apps can no longer see services that haven't been
exposed to them via the visibleToInstantApps attribute.

Change-Id: I6fd78067d1253825668d67b9e17dd3a0703f5d57
Fixes: 35871716
Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.EphemeralTest
parent 9220ff1f
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -310,11 +310,17 @@ public abstract class PackageManagerInternal {
            List<String> overlayPackageNames);

    /**
     * Resolves an intent, allowing instant apps to be resolved.
     * Resolves an activity intent, allowing instant apps to be resolved.
     */
    public abstract ResolveInfo resolveIntent(Intent intent, String resolvedType,
            int flags, int userId);

    /**
    * Resolves a service intent, allowing instant apps to be resolved.
    */
   public abstract ResolveInfo resolveService(Intent intent, String resolvedType,
           int flags, int userId, int callingUid);

    /**
     * Track the creator of a new isolated uid.
     * @param isolatedUid The newly created isolated uid.
+7 −6
Original line number Diff line number Diff line
@@ -398,7 +398,7 @@ public final class ActiveServices {
        r.delayedStop = false;
        r.fgRequired = fgRequired;
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                service, neededGrants));
                service, neededGrants, callingUid));

        final ServiceMap smap = getServiceMapLocked(r.userId);
        boolean addToStarting = false;
@@ -1355,10 +1355,10 @@ public final class ActiveServices {
        if (r == null) {
            try {
                // TODO: come back and remove this assumption to triage all services
                ResolveInfo rInfo = AppGlobals.getPackageManager().resolveService(service,
                ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
                        resolvedType, ActivityManagerService.STOCK_PM_FLAGS
                                | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                        userId);
                        userId, callingUid);
                ServiceInfo sInfo =
                    rInfo != null ? rInfo.serviceInfo : null;
                if (sInfo == null) {
@@ -1927,7 +1927,7 @@ public final class ActiveServices {
        // be called.
        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null));
                    null, null, 0));
        }

        sendServiceArgsLocked(r, execInFg, true);
@@ -1979,7 +1979,8 @@ public final class ActiveServices {
                    mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,
                            si.getUriPermissionsLocked());
                }
                // TODO b/34123112; Insert ephemeral grant here
                mAm.grantEphemeralAccessLocked(r.userId, si.intent,
                        r.appInfo.uid, UserHandle.getAppId(si.callingId));
                bumpServiceExecutingLocked(r, execInFg, "start");
                if (!oomAdjusted) {
                    oomAdjusted = true;
@@ -2591,7 +2592,7 @@ public final class ActiveServices {
                    stopServiceLocked(sr);
                } else {
                    sr.pendingStarts.add(new ServiceRecord.StartItem(sr, true,
                            sr.makeNextStartId(), baseIntent, null));
                            sr.makeNextStartId(), baseIntent, null, 0));
                    if (sr.app != null && sr.app.thread != null) {
                        // We always run in the foreground, since this is called as
                        // part of the "remove task" UI operation.
+3 −1
Original line number Diff line number Diff line
@@ -124,6 +124,7 @@ final class ServiceRecord extends Binder {
        final ServiceRecord sr;
        final boolean taskRemoved;
        final int id;
        final int callingId;
        final Intent intent;
        final ActivityManagerService.NeededUriGrants neededGrants;
        long deliveredTime;
@@ -134,12 +135,13 @@ final class ServiceRecord extends Binder {
        String stringName;      // caching of toString

        StartItem(ServiceRecord _sr, boolean _taskRemoved, int _id, Intent _intent,
                ActivityManagerService.NeededUriGrants _neededGrants) {
                ActivityManagerService.NeededUriGrants _neededGrants, int _callingId) {
            sr = _sr;
            taskRemoved = _taskRemoved;
            id = _id;
            intent = _intent;
            neededGrants = _neededGrants;
            callingId = _callingId;
        }

        UriPermissionOwner getUriPermissionsLocked() {
+155 −35
Original line number Diff line number Diff line
@@ -3036,13 +3036,14 @@ public class PackageManagerService extends IPackageManager.Stub {
            return null;
        }
        final int callingUid = Binder.getCallingUid();
        final int resolveFlags =
                MATCH_DIRECT_BOOT_AWARE
                | MATCH_DIRECT_BOOT_UNAWARE
                | (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0);
        final Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE);
        final List<ResolveInfo> resolvers = queryIntentServicesInternal(resolverIntent, null,
                resolveFlags, UserHandle.USER_SYSTEM);
                resolveFlags, UserHandle.USER_SYSTEM, callingUid, false /*includeInstantApps*/);
        final int N = resolvers.size();
        if (N == 0) {
@@ -4021,12 +4022,12 @@ public class PackageManagerService extends IPackageManager.Stub {
     * action and a {@code android.intent.category.BROWSABLE} category</li>
     * </ul>
     */
    int updateFlagsForResolve(int flags, int userId, Intent intent, boolean includeInstantApp) {
    int updateFlagsForResolve(int flags, int userId, Intent intent, int callingUid,
            boolean includeInstantApps) {
        // Safe mode means we shouldn't match any third-party components
        if (mSafeMode) {
            flags |= PackageManager.MATCH_SYSTEM_ONLY;
        }
        final int callingUid = Binder.getCallingUid();
        if (getInstantAppPackageName(callingUid) != null) {
            // But, ephemeral apps see both ephemeral and exposed, non-ephemeral components
            flags |= PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY;
@@ -4038,7 +4039,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                    || callingUid == Process.SHELL_UID
                    || callingUid == 0;
            final boolean allowMatchInstant =
                    (includeInstantApp
                    (includeInstantApps
                            && Intent.ACTION_VIEW.equals(intent.getAction())
                            && intent.hasCategory(Intent.CATEGORY_BROWSABLE)
                            && hasWebURI(intent))
@@ -5588,22 +5589,23 @@ public class PackageManagerService extends IPackageManager.Stub {
    public ResolveInfo resolveIntent(Intent intent, String resolvedType,
            int flags, int userId) {
        return resolveIntentInternal(
                intent, resolvedType, flags, userId, false /*includeInstantApp*/);
                intent, resolvedType, flags, userId, false /*includeInstantApps*/);
    }
    private ResolveInfo resolveIntentInternal(Intent intent, String resolvedType,
            int flags, int userId, boolean includeInstantApp) {
            int flags, int userId, boolean includeInstantApps) {
        try {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
            if (!sUserManager.exists(userId)) return null;
            flags = updateFlagsForResolve(flags, userId, intent, includeInstantApp);
            enforceCrossUserPermission(Binder.getCallingUid(), userId,
            final int callingUid = Binder.getCallingUid();
            flags = updateFlagsForResolve(flags, userId, intent, callingUid, includeInstantApps);
            enforceCrossUserPermission(callingUid, userId,
                    false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
            final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
                    flags, userId, includeInstantApp);
                    flags, userId, includeInstantApps);
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            final ResolveInfo bestChoice =
@@ -5623,9 +5625,11 @@ public class PackageManagerService extends IPackageManager.Stub {
        if (!sUserManager.exists(userId)) {
            return null;
        }
        final int callingUid = Binder.getCallingUid();
        intent = updateIntentForResolve(intent);
        final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
        final int flags = updateFlagsForResolve(0, userId, intent, false);
        final int flags = updateFlagsForResolve(
                0, userId, intent, callingUid, false /*includeInstantApps*/);
        final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
                userId);
        synchronized (mPackages) {
@@ -5914,7 +5918,9 @@ public class PackageManagerService extends IPackageManager.Stub {
            List<ResolveInfo> query, int priority, boolean always,
            boolean removeMatches, boolean debug, int userId) {
        if (!sUserManager.exists(userId)) return null;
        flags = updateFlagsForResolve(flags, userId, intent, false);
        final int callingUid = Binder.getCallingUid();
        flags = updateFlagsForResolve(
                flags, userId, intent, callingUid, false /*includeInstantApps*/);
        intent = updateIntentForResolve(intent);
        // writer
        synchronized (mPackages) {
@@ -6080,9 +6086,11 @@ public class PackageManagerService extends IPackageManager.Stub {
        }
        if (hasWebURI(intent)) {
            // cross-profile app linking works only towards the parent.
            final int callingUid = Binder.getCallingUid();
            final UserInfo parent = getProfileParent(sourceUserId);
            synchronized(mPackages) {
                int flags = updateFlagsForResolve(0, parent.id, intent, false);
                int flags = updateFlagsForResolve(0, parent.id, intent, callingUid,
                        false /*includeInstantApps*/);
                CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
                        intent, resolvedType, flags, sourceUserId, parent.id);
                return xpDomainInfo != null;
@@ -6149,11 +6157,12 @@ public class PackageManagerService extends IPackageManager.Stub {
    }
    private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
            String resolvedType, int flags, int userId, boolean includeInstantApp) {
            String resolvedType, int flags, int userId, boolean includeInstantApps) {
        if (!sUserManager.exists(userId)) return Collections.emptyList();
        final String instantAppPkgName = getInstantAppPackageName(Binder.getCallingUid());
        flags = updateFlagsForResolve(flags, userId, intent, includeInstantApp);
        enforceCrossUserPermission(Binder.getCallingUid(), userId,
        final int callingUid = Binder.getCallingUid();
        final String instantAppPkgName = getInstantAppPackageName(callingUid);
        flags = updateFlagsForResolve(flags, userId, intent, callingUid, includeInstantApps);
        enforceCrossUserPermission(callingUid, userId,
                false /* requireFullPermission */, false /* checkShell */,
                "query intent activities");
        ComponentName comp = intent.getComponent();
@@ -6783,8 +6792,10 @@ public class PackageManagerService extends IPackageManager.Stub {
            Intent[] specifics, String[] specificTypes, Intent intent,
            String resolvedType, int flags, int userId) {
        if (!sUserManager.exists(userId)) return Collections.emptyList();
        flags = updateFlagsForResolve(flags, userId, intent, false);
        enforceCrossUserPermission(Binder.getCallingUid(), userId,
        final int callingUid = Binder.getCallingUid();
        flags = updateFlagsForResolve(flags, userId, intent, callingUid,
                false /*includeInstantApps*/);
        enforceCrossUserPermission(callingUid, userId,
                false /*requireFullPermission*/, false /*checkShell*/,
                "query intent activity options");
        final String resultsAction = intent.getAction();
@@ -6963,7 +6974,9 @@ public class PackageManagerService extends IPackageManager.Stub {
    private @NonNull List<ResolveInfo> queryIntentReceiversInternal(Intent intent,
            String resolvedType, int flags, int userId) {
        if (!sUserManager.exists(userId)) return Collections.emptyList();
        flags = updateFlagsForResolve(flags, userId, intent, false);
        final int callingUid = Binder.getCallingUid();
        flags = updateFlagsForResolve(flags, userId, intent, callingUid,
                false /*includeInstantApps*/);
        ComponentName comp = intent.getComponent();
        if (comp == null) {
            if (intent.getSelector() != null) {
@@ -6999,9 +7012,17 @@ public class PackageManagerService extends IPackageManager.Stub {
    @Override
    public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
        final int callingUid = Binder.getCallingUid();
        return resolveServiceInternal(
                intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/);
    }
    private ResolveInfo resolveServiceInternal(Intent intent, String resolvedType, int flags,
            int userId, int callingUid, boolean includeInstantApps) {
        if (!sUserManager.exists(userId)) return null;
        flags = updateFlagsForResolve(flags, userId, intent, false);
        List<ResolveInfo> query = queryIntentServicesInternal(intent, resolvedType, flags, userId);
        flags = updateFlagsForResolve(flags, userId, intent, callingUid, includeInstantApps);
        List<ResolveInfo> query = queryIntentServicesInternal(
                intent, resolvedType, flags, userId, callingUid, includeInstantApps);
        if (query != null) {
            if (query.size() >= 1) {
                // If there is more than one service with the same priority,
@@ -7015,14 +7036,17 @@ public class PackageManagerService extends IPackageManager.Stub {
    @Override
    public @NonNull ParceledListSlice<ResolveInfo> queryIntentServices(Intent intent,
            String resolvedType, int flags, int userId) {
        return new ParceledListSlice<>(
                queryIntentServicesInternal(intent, resolvedType, flags, userId));
        final int callingUid = Binder.getCallingUid();
        return new ParceledListSlice<>(queryIntentServicesInternal(
                intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/));
    }
    private @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
            String resolvedType, int flags, int userId) {
            String resolvedType, int flags, int userId, int callingUid,
            boolean includeInstantApps) {
        if (!sUserManager.exists(userId)) return Collections.emptyList();
        flags = updateFlagsForResolve(flags, userId, intent, false);
        final String instantAppPkgName = getInstantAppPackageName(callingUid);
        flags = updateFlagsForResolve(flags, userId, intent, callingUid, includeInstantApps);
        ComponentName comp = intent.getComponent();
        if (comp == null) {
            if (intent.getSelector() != null) {
@@ -7034,10 +7058,28 @@ public class PackageManagerService extends IPackageManager.Stub {
            final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
            final ServiceInfo si = getServiceInfo(comp, flags, userId);
            if (si != null) {
                // When specifying an explicit component, we prevent the service from being
                // used when either 1) the service is in an instant application and the
                // caller is not the same instant application or 2) the calling package is
                // ephemeral and the activity is not visible to ephemeral applications.
                final boolean matchVisibleToInstantAppOnly =
                        (flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
                final boolean isCallerInstantApp =
                        instantAppPkgName != null;
                final boolean isTargetSameInstantApp =
                        comp.getPackageName().equals(instantAppPkgName);
                final boolean isTargetHiddenFromInstantApp =
                        (si.flags & ServiceInfo.FLAG_VISIBLE_TO_EPHEMERAL) == 0;
                final boolean blockResolution =
                        !isTargetSameInstantApp
                        && ((matchVisibleToInstantAppOnly && isCallerInstantApp
                                        && isTargetHiddenFromInstantApp));
                if (!blockResolution) {
                    final ResolveInfo ri = new ResolveInfo();
                    ri.serviceInfo = si;
                    list.add(ri);
                }
            }
            return list;
        }
@@ -7045,17 +7087,67 @@ public class PackageManagerService extends IPackageManager.Stub {
        synchronized (mPackages) {
            String pkgName = intent.getPackage();
            if (pkgName == null) {
                return mServices.queryIntent(intent, resolvedType, flags, userId);
                return applyPostServiceResolutionFilter(
                        mServices.queryIntent(intent, resolvedType, flags, userId),
                        instantAppPkgName);
            }
            final PackageParser.Package pkg = mPackages.get(pkgName);
            if (pkg != null) {
                return mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services,
                        userId);
                return applyPostServiceResolutionFilter(
                        mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services,
                                userId),
                        instantAppPkgName);
            }
            return Collections.emptyList();
        }
    }
    private List<ResolveInfo> applyPostServiceResolutionFilter(List<ResolveInfo> resolveInfos,
            String instantAppPkgName) {
        // TODO: When adding on-demand split support for non-instant apps, remove this check
        // and always apply post filtering
        if (instantAppPkgName == null) {
            return resolveInfos;
        }
        for (int i = resolveInfos.size() - 1; i >= 0; i--) {
            final ResolveInfo info = resolveInfos.get(i);
            final boolean isEphemeralApp = info.serviceInfo.applicationInfo.isInstantApp();
            // allow services that are defined in the provided package
            if (isEphemeralApp && instantAppPkgName.equals(info.serviceInfo.packageName)) {
                if (info.serviceInfo.splitName != null
                        && !ArrayUtils.contains(info.serviceInfo.applicationInfo.splitNames,
                                info.serviceInfo.splitName)) {
                    // requested service is defined in a split that hasn't been installed yet.
                    // add the installer to the resolve list
                    if (DEBUG_EPHEMERAL) {
                        Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
                    }
                    final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
                    installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
                            info.serviceInfo.packageName, info.serviceInfo.splitName,
                            info.serviceInfo.applicationInfo.versionCode);
                    // make sure this resolver is the default
                    installerInfo.isDefault = true;
                    installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
                            | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
                    // add a non-generic filter
                    installerInfo.filter = new IntentFilter();
                    // load resources from the correct package
                    installerInfo.resolvePackageName = info.getComponentInfo().packageName;
                    resolveInfos.set(i, installerInfo);
                }
                continue;
            }
            // allow services that have been explicitly exposed to ephemeral apps
            if (!isEphemeralApp
                    && ((info.serviceInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL) != 0)) {
                continue;
            }
            resolveInfos.remove(i);
        }
        return resolveInfos;
    }
    @Override
    public @NonNull ParceledListSlice<ResolveInfo> queryIntentContentProviders(Intent intent,
            String resolvedType, int flags, int userId) {
@@ -7066,7 +7158,9 @@ public class PackageManagerService extends IPackageManager.Stub {
    private @NonNull List<ResolveInfo> queryIntentContentProvidersInternal(
            Intent intent, String resolvedType, int flags, int userId) {
        if (!sUserManager.exists(userId)) return Collections.emptyList();
        flags = updateFlagsForResolve(flags, userId, intent, false);
        final int callingUid = Binder.getCallingUid();
        flags = updateFlagsForResolve(flags, userId, intent, callingUid,
                false /*includeInstantApps*/);
        ComponentName comp = intent.getComponent();
        if (comp == null) {
            if (intent.getSelector() != null) {
@@ -12401,11 +12495,29 @@ public class PackageManagerService extends IPackageManager.Stub {
            if (ps == null) {
                return null;
            }
            final PackageUserState userState = ps.readUserState(userId);
            ServiceInfo si = PackageParser.generateServiceInfo(service, mFlags,
                    ps.readUserState(userId), userId);
                    userState, userId);
            if (si == null) {
                return null;
            }
            final boolean matchVisibleToInstantApp =
                    (mFlags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
            final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
            // throw out filters that aren't visible to ephemeral apps
            if (matchVisibleToInstantApp
                    && !(info.isVisibleToInstantApp() || userState.instantApp)) {
                return null;
            }
            // throw out ephemeral filters if we're not explicitly requesting them
            if (!isInstantApp && userState.instantApp) {
                return null;
            }
            // throw out instant app filters if updates are available; will trigger
            // instant app resolution
            if (userState.instantApp && ps.isUpdateAvailable()) {
                return null;
            }
            final ResolveInfo res = new ResolveInfo();
            res.serviceInfo = si;
            if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
@@ -23146,10 +23258,18 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
            }
        }
        @Override
        public ResolveInfo resolveIntent(Intent intent, String resolvedType,
                int flags, int userId) {
            return resolveIntentInternal(
                    intent, resolvedType, flags, userId, true /*includeInstantApp*/);
                    intent, resolvedType, flags, userId, true /*includeInstantApps*/);
        }
        @Override
        public ResolveInfo resolveService(Intent intent, String resolvedType,
                int flags, int userId, int callingUid) {
            return resolveServiceInternal(
                    intent, resolvedType, flags, userId, callingUid, true /*includeInstantApps*/);
        }
+1 −1
Original line number Diff line number Diff line
@@ -3375,7 +3375,7 @@ final class Settings {
    private void applyDefaultPreferredActivityLPw(PackageManagerService service,
            Intent intent, int flags, ComponentName cn, String scheme, PatternMatcher ssp,
            IntentFilter.AuthorityEntry auth, PatternMatcher path, int userId) {
        flags = service.updateFlagsForResolve(flags, userId, intent, false);
        flags = service.updateFlagsForResolve(flags, userId, intent, Binder.getCallingUid(), false);
        List<ResolveInfo> ri = service.mActivities.queryIntent(intent,
                intent.getType(), flags, 0);
        if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Queried " + intent