From bf6154a5ba3ec164d5f29465dcb65213cc641b22 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Fri, 26 Aug 2016 13:32:52 -0700 Subject: [PATCH] Allow package verifier and uninstaller to do silent uninstalls. Bug: 30280938 Bug: 31146793 Change-Id: I450340d9bafd3c1b7c1bfb8ae9281a23cb8a0b5e --- .../android/server/pm/PackageManagerService.java | 64 ++++++++++++++++++---- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 38b5b149f412..65924c0ce8ae 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -455,6 +455,8 @@ public class PackageManagerService extends IPackageManager.Stub { private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; + private static final String PACKAGE_SCHEME = "package"; + private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay"; private static int DEFAULT_EPHEMERAL_HASH_PREFIX_MASK = 0xFFFFF000; @@ -1118,6 +1120,7 @@ public class PackageManagerService extends IPackageManager.Stub { final @Nullable String mRequiredVerifierPackage; final @NonNull String mRequiredInstallerPackage; + final @NonNull String mRequiredUninstallerPackage; final @Nullable String mSetupWizardPackage; final @NonNull String mServicesSystemSharedLibraryPackageName; final @NonNull String mSharedSystemSharedLibraryPackageName; @@ -2623,6 +2626,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (!mOnlyCore) { mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr(); mRequiredInstallerPackage = getRequiredInstallerLPr(); + mRequiredUninstallerPackage = getRequiredUninstallerLPr(); mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr(); mIntentFilterVerifier = new IntentVerifierProxy(mContext, mIntentFilterVerifierComponent); @@ -2633,6 +2637,7 @@ public class PackageManagerService extends IPackageManager.Stub { } else { mRequiredVerifierPackage = null; mRequiredInstallerPackage = null; + mRequiredUninstallerPackage = null; mIntentFilterVerifierComponent = null; mIntentFilterVerifier = null; mServicesSystemSharedLibraryPackageName = null; @@ -2745,6 +2750,22 @@ public class PackageManagerService extends IPackageManager.Stub { } } + private @NonNull String getRequiredUninstallerLPr() { + final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.setData(Uri.fromParts(PACKAGE_SCHEME, "foo.bar", null)); + + final ResolveInfo resolveInfo = resolveIntent(intent, null, + MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, + UserHandle.USER_SYSTEM); + if (resolveInfo == null || + mResolveActivity.name.equals(resolveInfo.getComponentInfo().name)) { + throw new RuntimeException("There must be exactly one uninstaller; found " + + resolveInfo); + } + return resolveInfo.getComponentInfo().packageName; + } + private @NonNull ComponentName getIntentFilterVerifierComponentNameLPr() { final Intent intent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION); @@ -11266,7 +11287,7 @@ public class PackageManagerService extends IPackageManager.Stub { } for (int id : resolvedUserIds) { final Intent intent = new Intent(action, - pkg != null ? Uri.fromParts("package", pkg, null) : null); + pkg != null ? Uri.fromParts(PACKAGE_SCHEME, pkg, null) : null); if (extras != null) { intent.putExtras(extras); } @@ -11762,6 +11783,12 @@ public class PackageManagerService extends IPackageManager.Stub { return false; } + if (packageName.equals(mRequiredUninstallerPackage)) { + Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName + + "\": required for package uninstallation"); + return false; + } + if (packageName.equals(mRequiredVerifierPackage)) { Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName + "\": required for package verification"); @@ -15326,13 +15353,11 @@ public class PackageManagerService extends IPackageManager.Stub { Preconditions.checkNotNull(packageName); Preconditions.checkNotNull(observer); final int uid = Binder.getCallingUid(); - if (uid != Process.SHELL_UID && uid != Process.ROOT_UID && uid != Process.SYSTEM_UID - && uid != getPackageUid(mRequiredInstallerPackage, 0, UserHandle.getUserId(uid)) - && !isOrphaned(packageName) - && !isCallerSameAsInstaller(uid, packageName)) { + if (!isOrphaned(packageName) + && !isCallerAllowedToSilentlyUninstall(uid, packageName)) { try { final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); - intent.setData(Uri.fromParts("package", packageName, null)); + intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null)); intent.putExtra(PackageInstaller.EXTRA_CALLBACK, observer.asBinder()); observer.onUserActionRequired(intent); } catch (RemoteException re) { @@ -15407,10 +15432,29 @@ public class PackageManagerService extends IPackageManager.Stub { }); } - private boolean isCallerSameAsInstaller(int callingUid, String pkgName) { - final int installerPkgUid = getPackageUid(getInstallerPackageName(pkgName), - 0 /* flags */, UserHandle.getUserId(callingUid)); - return installerPkgUid == callingUid; + private boolean isCallerAllowedToSilentlyUninstall(int callingUid, String pkgName) { + if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID + || callingUid == Process.SYSTEM_UID) { + return true; + } + final int callingUserId = UserHandle.getUserId(callingUid); + // If the caller installed the pkgName, then allow it to silently uninstall. + if (callingUid == getPackageUid(getInstallerPackageName(pkgName), 0, callingUserId)) { + return true; + } + + // Allow package verifier to silently uninstall. + if (mRequiredVerifierPackage != null && + callingUid == getPackageUid(mRequiredVerifierPackage, 0, callingUserId)) { + return true; + } + + // Allow package uninstaller to silently uninstall. + if (mRequiredUninstallerPackage != null && + callingUid == getPackageUid(mRequiredUninstallerPackage, 0, callingUserId)) { + return true; + } + return false; } private int[] getBlockUninstallForUsers(String packageName, int[] userIds) { -- 2.11.0