From c06c0306717d0e1fc132541127f3657e937f02f4 Mon Sep 17 00:00:00 2001 From: Todd Kennedy Date: Mon, 10 Apr 2017 14:57:19 -0700 Subject: [PATCH] Filter instant app content providers Only expose the correct content providers depending upon which component defines/exposes them. Change-Id: I283c787165e33d9515068487f83de6d28616b427 Fixes: 35871462 Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.EphemeralTest --- .../android/server/pm/PackageManagerService.java | 147 +++++++++++++++++++-- 1 file changed, 133 insertions(+), 14 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index dd3959001f44..07de2d9e4b78 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -7094,17 +7094,23 @@ public class PackageManagerService extends IPackageManager.Stub { // 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 matchInstantApp = + (flags & PackageManager.MATCH_INSTANT) != 0; 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 isTargetInstantApp = + (si.applicationInfo.privateFlags + & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0; final boolean isTargetHiddenFromInstantApp = (si.flags & ServiceInfo.FLAG_VISIBLE_TO_EPHEMERAL) == 0; final boolean blockResolution = !isTargetSameInstantApp - && ((matchVisibleToInstantAppOnly && isCallerInstantApp + && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp) + || (matchVisibleToInstantAppOnly && isCallerInstantApp && isTargetHiddenFromInstantApp)); if (!blockResolution) { final ResolveInfo ri = new ResolveInfo(); @@ -7191,6 +7197,7 @@ public class PackageManagerService extends IPackageManager.Stub { Intent intent, String resolvedType, int flags, int userId) { if (!sUserManager.exists(userId)) return Collections.emptyList(); final int callingUid = Binder.getCallingUid(); + final String instantAppPkgName = getInstantAppPackageName(callingUid); flags = updateFlagsForResolve(flags, userId, intent, callingUid, false /*includeInstantApps*/); ComponentName comp = intent.getComponent(); @@ -7204,9 +7211,33 @@ public class PackageManagerService extends IPackageManager.Stub { final List list = new ArrayList(1); final ProviderInfo pi = getProviderInfo(comp, flags, userId); if (pi != null) { - final ResolveInfo ri = new ResolveInfo(); - ri.providerInfo = pi; - list.add(ri); + // When specifying an explicit component, we prevent the provider from being + // used when either 1) the provider is in an instant application and the + // caller is not the same instant application or 2) the calling package is an + // instant application and the provider is not visible to instant applications. + final boolean matchInstantApp = + (flags & PackageManager.MATCH_INSTANT) != 0; + 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 isTargetInstantApp = + (pi.applicationInfo.privateFlags + & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0; + final boolean isTargetHiddenFromInstantApp = + (pi.flags & ProviderInfo.FLAG_VISIBLE_TO_EPHEMERAL) == 0; + final boolean blockResolution = + !isTargetSameInstantApp + && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp) + || (matchVisibleToInstantAppOnly && isCallerInstantApp + && isTargetHiddenFromInstantApp)); + if (!blockResolution) { + final ResolveInfo ri = new ResolveInfo(); + ri.providerInfo = pi; + list.add(ri); + } } return list; } @@ -7215,17 +7246,67 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { String pkgName = intent.getPackage(); if (pkgName == null) { - return mProviders.queryIntent(intent, resolvedType, flags, userId); + return applyPostContentProviderResolutionFilter( + mProviders.queryIntent(intent, resolvedType, flags, userId), + instantAppPkgName); } final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { - return mProviders.queryIntentForPackage( - intent, resolvedType, flags, pkg.providers, userId); + return applyPostContentProviderResolutionFilter( + mProviders.queryIntentForPackage( + intent, resolvedType, flags, pkg.providers, userId), + instantAppPkgName); } return Collections.emptyList(); } } + private List applyPostContentProviderResolutionFilter( + List resolveInfos, String instantAppPkgName) { + // TODO: When adding on-demand split support for non-instant applications, 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.providerInfo.applicationInfo.isInstantApp(); + // allow providers that are defined in the provided package + if (isEphemeralApp && instantAppPkgName.equals(info.providerInfo.packageName)) { + if (info.providerInfo.splitName != null + && !ArrayUtils.contains(info.providerInfo.applicationInfo.splitNames, + info.providerInfo.splitName)) { + // requested provider 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.providerInfo.packageName, info.providerInfo.splitName, + info.providerInfo.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 providers that have been explicitly exposed to instant applications + if (!isEphemeralApp + && ((info.providerInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL) != 0)) { + continue; + } + resolveInfos.remove(i); + } + return resolveInfos; + } + @Override public ParceledListSlice getInstalledPackages(int flags, int userId) { if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList(); @@ -7557,17 +7638,38 @@ public class PackageManagerService extends IPackageManager.Stub { public ProviderInfo resolveContentProvider(String name, int flags, int userId) { if (!sUserManager.exists(userId)) return null; flags = updateFlagsForComponent(flags, userId, name); + final String instantAppPkgName = getInstantAppPackageName(Binder.getCallingUid()); // reader synchronized (mPackages) { final PackageParser.Provider provider = mProvidersByAuthority.get(name); PackageSetting ps = provider != null ? mSettings.mPackages.get(provider.owner.packageName) : null; - return ps != null - && mSettings.isEnabledAndMatchLPr(provider.info, flags, userId) - ? PackageParser.generateProviderInfo(provider, flags, - ps.readUserState(userId), userId) - : null; + if (ps != null) { + final boolean isInstantApp = ps.getInstantApp(userId); + // normal application; filter out instant application provider + if (instantAppPkgName == null && isInstantApp) { + return null; + } + // instant application; filter out other instant applications + if (instantAppPkgName != null + && isInstantApp + && !provider.owner.packageName.equals(instantAppPkgName)) { + return null; + } + // instant application; filter out non-exposed provider + if (instantAppPkgName != null + && (provider.info.flags & ProviderInfo.FLAG_VISIBLE_TO_EPHEMERAL) == 0) { + return null; + } + // provider not enabled + if (!mSettings.isEnabledAndMatchLPr(provider.info, flags, userId)) { + return null; + } + return PackageParser.generateProviderInfo( + provider, flags, ps.readUserState(userId), userId); + } + return null; } } @@ -12772,8 +12874,26 @@ public class PackageManagerService extends IPackageManager.Stub { if (ps == null) { return null; } + final PackageUserState userState = ps.readUserState(userId); + 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 instant applications + if (matchVisibleToInstantApp + && !(info.isVisibleToInstantApp() || userState.instantApp)) { + return null; + } + // throw out instant application filters if we're not explicitly requesting them + if (!isInstantApp && userState.instantApp) { + return null; + } + // throw out instant application filters if updates are available; will trigger + // instant application resolution + if (userState.instantApp && ps.isUpdateAvailable()) { + return null; + } ProviderInfo pi = PackageParser.generateProviderInfo(provider, mFlags, - ps.readUserState(userId), userId); + userState, userId); if (pi == null) { return null; } @@ -23338,7 +23458,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); intent, resolvedType, flags, userId, callingUid, true /*includeInstantApps*/); } - @Override public void addIsolatedUid(int isolatedUid, int ownerUid) { synchronized (mPackages) { -- 2.11.0