Add additional checks on received uninstall request
Checks if the caller has uninstall permission and appOp, and if the app being uninstalled actually exists.
Bug: 182205982
Test: builds successfully
Test: No CTS Tests. Flag to use new app is turned off by default
Change-Id: Ia19802845c049979cee745835d720a4f9b666aef
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/UninstallRepository.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/UninstallRepository.java
index 3a0e1e3..abf8a34 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/UninstallRepository.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/UninstallRepository.java
@@ -16,18 +16,26 @@
package com.android.packageinstaller.v2.model;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static com.android.packageinstaller.v2.model.PackageUtil.getMaxTargetSdkVersionForUid;
+import static com.android.packageinstaller.v2.model.PackageUtil.getPackageNameForUid;
+import static com.android.packageinstaller.v2.model.PackageUtil.isPermissionGranted;
import static com.android.packageinstaller.v2.model.uninstallstagedata.UninstallAborted.ABORT_REASON_APP_UNAVAILABLE;
import static com.android.packageinstaller.v2.model.uninstallstagedata.UninstallAborted.ABORT_REASON_GENERIC_ERROR;
import static com.android.packageinstaller.v2.model.uninstallstagedata.UninstallAborted.ABORT_REASON_USER_NOT_ALLOWED;
+import android.Manifest;
+import android.app.AppOpsManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.UninstallCompleteCallback;
import android.net.Uri;
+import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
@@ -41,10 +49,12 @@
private static final String TAG = UninstallRepository.class.getSimpleName();
private final Context mContext;
+ private final AppOpsManager mAppOpsManager;
private final PackageManager mPackageManager;
private final UserManager mUserManager;
public UserHandle mUninstalledUser;
public UninstallCompleteCallback mCallback;
+ private ApplicationInfo mTargetAppInfo;
private ActivityInfo mTargetActivityInfo;
private Intent mIntent;
private String mTargetPackageName;
@@ -53,6 +63,7 @@
public UninstallRepository(Context context) {
mContext = context;
+ mAppOpsManager = context.getSystemService(AppOpsManager.class);
mPackageManager = context.getPackageManager();
mUserManager = context.getSystemService(UserManager.class);
}
@@ -69,6 +80,30 @@
// TODO: should we give any indication to the user?
}
+ String callingPackage = getPackageNameForUid(mContext, callingUid, null);
+ if (callingPackage == null) {
+ Log.e(TAG, "Package not found for originating uid " + callingUid);
+ return new UninstallAborted(ABORT_REASON_GENERIC_ERROR);
+ } else {
+ if (mAppOpsManager.noteOpNoThrow(
+ AppOpsManager.OPSTR_REQUEST_DELETE_PACKAGES, callingUid, callingPackage)
+ != MODE_ALLOWED) {
+ Log.e(TAG, "Install from uid " + callingUid + " disallowed by AppOps");
+ return new UninstallAborted(ABORT_REASON_GENERIC_ERROR);
+ }
+ }
+
+ if (getMaxTargetSdkVersionForUid(mContext, callingUid) >= Build.VERSION_CODES.P
+ && !isPermissionGranted(mContext, Manifest.permission.REQUEST_DELETE_PACKAGES,
+ callingUid)
+ && !isPermissionGranted(mContext, Manifest.permission.DELETE_PACKAGES, callingUid)) {
+ Log.e(TAG, "Uid " + callingUid + " does not have "
+ + Manifest.permission.REQUEST_DELETE_PACKAGES + " or "
+ + Manifest.permission.DELETE_PACKAGES);
+
+ return new UninstallAborted(ABORT_REASON_GENERIC_ERROR);
+ }
+
// Get intent information.
// We expect an intent with URI of the form package:<packageName>#<className>
// className is optional; if specified, it is the activity the user chose to uninstall
@@ -105,6 +140,18 @@
mCallback = intent.getParcelableExtra(PackageInstaller.EXTRA_CALLBACK,
PackageManager.UninstallCompleteCallback.class);
+ try {
+ mTargetAppInfo = mPackageManager.getApplicationInfo(mTargetPackageName,
+ PackageManager.ApplicationInfoFlags.of(PackageManager.MATCH_ANY_USER));
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Unable to get packageName");
+ }
+
+ if (mTargetAppInfo == null) {
+ Log.e(TAG, "Invalid packageName: " + mTargetPackageName);
+ return new UninstallAborted(ABORT_REASON_APP_UNAVAILABLE);
+ }
+
// The class name may have been specified (e.g. when deleting an app from all apps)
final String className = packageUri.getFragment();
if (className != null) {