OSDN Git Service

Implement service filtering
authorTodd Kennedy <toddke@google.com>
Fri, 31 Mar 2017 00:50:42 +0000 (17:50 -0700)
committerTodd Kennedy <toddke@google.com>
Fri, 31 Mar 2017 21:30:42 +0000 (14:30 -0700)
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

core/java/android/content/pm/PackageManagerInternal.java
services/core/java/com/android/server/am/ActiveServices.java
services/core/java/com/android/server/am/ServiceRecord.java
services/core/java/com/android/server/pm/PackageManagerService.java
services/core/java/com/android/server/pm/Settings.java

index 16d582e..7bfde75 100644 (file)
@@ -310,12 +310,18 @@ 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.
      * @param ownerUid The uid of the app that created the isolated process.
index 8b0665c..9ad945f 100644 (file)
@@ -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.
index 44ebf50..b57f6c3 100644 (file)
@@ -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() {
index 2115f31..e3b55f0 100644 (file)
@@ -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,9 +6792,11 @@ 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,
-                false /* requireFullPermission */, false /* checkShell */,
+        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,9 +7058,27 @@ public class PackageManagerService extends IPackageManager.Stub {
             final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
             final ServiceInfo si = getServiceInfo(comp, flags, userId);
             if (si != null) {
-                final ResolveInfo ri = new ResolveInfo();
-                ri.serviceInfo = si;
-                list.add(ri);
+                // 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*/);
         }
 
 
index 8739089..6fb056a 100644 (file)
@@ -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