From d81a7d0088a1b37edf4249189d18f556bfce0aac Mon Sep 17 00:00:00 2001 From: Sumedh Sen Date: Mon, 11 Jul 2022 10:53:46 -0700 Subject: [PATCH] Prevent apps from accessing protected content providers without query permission -If a package tried to access a protected content provider (i.e. a content provider with grantUriPermission=false), without having adequate visibility, calling package would force close due to a SecurityException. -InstallStart now checks if the calling package has visibility of the package defining the content provider and also handles the SecurityException if raised. Bug: 195963690 Test: atest CtsContentProviderTestsWithVisibility CtsContentProviderTestsWithoutvisibility Change-Id: I50ee644461402a6aa9885958b763dc3d1bc07562 --- .../packageinstaller/InstallStart.java | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java index af05078b4f3ad..ac1a574f12cc6 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java @@ -19,6 +19,7 @@ package com.android.packageinstaller; import static com.android.packageinstaller.PackageUtil.getMaxTargetSdkVersionForUid; import android.Manifest; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; @@ -28,12 +29,12 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ProviderInfo; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.RemoteException; -import android.os.UserManager; import android.util.Log; import java.util.Arrays; @@ -47,14 +48,12 @@ public class InstallStart extends Activity { private static final String DOWNLOADS_AUTHORITY = "downloads"; private PackageManager mPackageManager; - private UserManager mUserManager; private boolean mAbortInstall = false; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mPackageManager = getPackageManager(); - mUserManager = getSystemService(UserManager.class); Intent intent = getIntent(); String callingPackage = getCallingPackage(); String callingAttributionTag = null; @@ -119,8 +118,9 @@ public class InstallStart extends Activity { } else { Uri packageUri = intent.getData(); - if (packageUri != null && packageUri.getScheme().equals( - ContentResolver.SCHEME_CONTENT)) { + if (packageUri != null + && packageUri.getScheme().equals(ContentResolver.SCHEME_CONTENT) + && canPackageQuery(originatingUid, packageUri)) { // [IMPORTANT] This path is deprecated, but should still work. Only necessary // features should be added. @@ -140,7 +140,14 @@ public class InstallStart extends Activity { } if (nextActivity != null) { - startActivity(nextActivity); + try { + startActivity(nextActivity); + } catch (SecurityException e) { + Intent result = new Intent(); + result.putExtra(Intent.EXTRA_INSTALL_RESULT, + PackageManager.INSTALL_FAILED_INVALID_URI); + setResult(RESULT_FIRST_USER, result); + } } finish(); } @@ -229,4 +236,21 @@ public class InstallStart extends Activity { final ApplicationInfo appInfo = downloadProviderPackage.applicationInfo; return (appInfo.isSystemApp() && uid == appInfo.uid); } + + @NonNull + private boolean canPackageQuery(int originatingUid, Uri packageUri) { + String callingPackage = mPackageManager.getPackagesForUid(originatingUid)[0]; + ProviderInfo info = mPackageManager.resolveContentProvider(packageUri.getAuthority(), + PackageManager.ComponentInfoFlags.of(0)); + if (info == null) { + return false; + } + String targetPackage = info.packageName; + + try { + return mPackageManager.canPackageQuery(callingPackage, targetPackage); + } catch (NameNotFoundException e) { + return false; + } + } }