diff options
| author | 2023-05-09 16:08:17 -0700 | |
|---|---|---|
| committer | 2023-05-09 16:35:52 -0700 | |
| commit | cc045c8cf82fd0968963d414fd0939797e5827a5 (patch) | |
| tree | 8427067e059c0a09d1594e1d614b9b88122b0bac | |
| parent | f3192865a3508ecb46959d93685f6087e182eaab (diff) | |
Perform user restriction check before creating install session
If a user is restricted with DISALLOW_INSTALL_APPS restriction,
PackageInstallerSession throws a SecurityException causing PIA to crash.
Perform restriction checks before PIA creates an install session
Test: atest CtsPackageInstallTestCases:UserRestrictionInstallTest
Bug: 280441684
Change-Id: I9e6b9a0e56eea122b17b4e75a5496d158b15eefe
3 files changed, 158 insertions, 108 deletions
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java index 3f98867cb267..229b7a73a2a3 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java @@ -20,6 +20,8 @@ import static com.android.packageinstaller.PackageUtil.getMaxTargetSdkVersionFor import android.Manifest; import android.app.Activity; +import android.app.DialogFragment; +import android.app.admin.DevicePolicyManager; import android.content.ContentResolver; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -31,6 +33,8 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Process; +import android.os.UserManager; +import android.provider.Settings; import android.text.TextUtils; import android.util.EventLog; import android.util.Log; @@ -45,16 +49,24 @@ import java.util.Arrays; * it. */ public class InstallStart extends Activity { - private static final String LOG_TAG = InstallStart.class.getSimpleName(); + private static final String TAG = InstallStart.class.getSimpleName(); private static final String DOWNLOADS_AUTHORITY = "downloads"; + + private static final int DLG_INSTALL_APPS_RESTRICTED_FOR_USER = 1; + private static final int DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER = 2; private PackageManager mPackageManager; + private UserManager mUserManager; private boolean mAbortInstall = false; + private final boolean mLocalLOGV = 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; @@ -80,8 +92,7 @@ public class InstallStart extends Activity { // Uid of the source package, coming from ActivityManager int callingUid = getLaunchedFromUid(); if (callingUid == Process.INVALID_UID) { - // Cannot reach ActivityManager. Aborting install. - Log.e(LOG_TAG, "Could not determine the launching uid."); + Log.e(TAG, "Could not determine the launching uid."); } // Uid of the source package, with a preference to uid from ApplicationInfo final int originatingUid = sourceInfo != null ? sourceInfo.uid : callingUid; @@ -104,12 +115,12 @@ public class InstallStart extends Activity { && originatingUid != Process.INVALID_UID) { final int targetSdkVersion = getMaxTargetSdkVersionForUid(this, originatingUid); if (targetSdkVersion < 0) { - Log.w(LOG_TAG, "Cannot get target sdk version for uid " + originatingUid); + Log.w(TAG, "Cannot get target sdk version for uid " + originatingUid); // Invalid originating uid supplied. Abort install. mAbortInstall = true; } else if (targetSdkVersion >= Build.VERSION_CODES.O && !isUidRequestingPermission( originatingUid, Manifest.permission.REQUEST_INSTALL_PACKAGES)) { - Log.e(LOG_TAG, "Requesting uid " + originatingUid + " needs to declare permission " + Log.e(TAG, "Requesting uid " + originatingUid + " needs to declare permission " + Manifest.permission.REQUEST_INSTALL_PACKAGES); mAbortInstall = true; } @@ -119,6 +130,8 @@ public class InstallStart extends Activity { mAbortInstall = true; } + checkDevicePolicyRestriction(); + final String installerPackageNameFromIntent = getIntent().getStringExtra( Intent.EXTRA_INSTALLER_PACKAGE_NAME); if (installerPackageNameFromIntent != null) { @@ -126,7 +139,7 @@ public class InstallStart extends Activity { if (!TextUtils.equals(installerPackageNameFromIntent, callingPkgName) && mPackageManager.checkPermission(Manifest.permission.INSTALL_PACKAGES, callingPkgName) != PackageManager.PERMISSION_GRANTED) { - Log.e(LOG_TAG, "The given installer package name " + installerPackageNameFromIntent + Log.e(TAG, "The given installer package name " + installerPackageNameFromIntent + " is invalid. Remove it."); EventLog.writeEvent(0x534e4554, "236687884", getLaunchedFromUid(), "Invalid EXTRA_INSTALLER_PACKAGE_NAME"); @@ -270,4 +283,97 @@ public class InstallStart extends Activity { int installerUid = packageInstaller.getSessionInfo(sessionId).getInstallerUid(); return (originatingUid == Process.ROOT_UID) || (originatingUid == installerUid); } + + private void checkDevicePolicyRestriction() { + // Check for install apps user restriction first. + final int installAppsRestrictionSource = mUserManager.getUserRestrictionSource( + UserManager.DISALLOW_INSTALL_APPS, Process.myUserHandle()); + if ((installAppsRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) { + if (mLocalLOGV) Log.i(TAG, "install not allowed: " + UserManager.DISALLOW_INSTALL_APPS); + mAbortInstall = true; + showDialogInner(DLG_INSTALL_APPS_RESTRICTED_FOR_USER); + return; + } else if (installAppsRestrictionSource != UserManager.RESTRICTION_NOT_SET) { + if (mLocalLOGV) { + Log.i(TAG, "install not allowed by admin; showing " + + Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS); + } + mAbortInstall = true; + startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS)); + return; + } + + final int unknownSourcesRestrictionSource = mUserManager.getUserRestrictionSource( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, Process.myUserHandle()); + final int unknownSourcesGlobalRestrictionSource = mUserManager.getUserRestrictionSource( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, Process.myUserHandle()); + final int systemRestriction = UserManager.RESTRICTION_SOURCE_SYSTEM + & (unknownSourcesRestrictionSource | unknownSourcesGlobalRestrictionSource); + if (systemRestriction != 0) { + if (mLocalLOGV) Log.i(TAG, "Showing DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER"); + mAbortInstall = true; + showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER); + } else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET) { + mAbortInstall = true; + startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); + } else if (unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) { + mAbortInstall = true; + startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY); + } + } + + /** + * Replace any dialog shown by the dialog with the one for the given {@link #createDialog(int)}. + * + * @param id The dialog type to add + */ + private void showDialogInner(int id) { + if (mLocalLOGV) Log.i(TAG, "showDialogInner(" + id + ")"); + DialogFragment currentDialog = + (DialogFragment) getFragmentManager().findFragmentByTag("dialog"); + if (currentDialog != null) { + currentDialog.dismissAllowingStateLoss(); + } + + DialogFragment newDialog = createDialog(id); + if (newDialog != null) { + getFragmentManager().beginTransaction() + .add(newDialog, "dialog").commitAllowingStateLoss(); + } + } + + /** + * Create a new dialog. + * + * @param id The id of the dialog (determines dialog type) + * + * @return The dialog + */ + private DialogFragment createDialog(int id) { + if (mLocalLOGV) Log.i(TAG, "createDialog(" + id + ")"); + switch (id) { + case DLG_INSTALL_APPS_RESTRICTED_FOR_USER: + return PackageUtil.SimpleErrorDialog.newInstance( + R.string.install_apps_user_restriction_dlg_text); + case DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER: + return PackageUtil.SimpleErrorDialog.newInstance( + R.string.unknown_apps_user_restriction_dlg_text); + } + return null; + } + + private void startAdminSupportDetailsActivity(String restriction) { + if (mLocalLOGV) Log.i(TAG, "startAdminSupportDetailsActivity(): " + restriction); + + // If the given restriction is set by an admin, display information about the + // admin enforcing the restriction for the affected user. + final DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class); + final Intent showAdminSupportDetailsIntent = dpm.createAdminSupportIntent(restriction); + if (showAdminSupportDetailsIntent != null) { + if (mLocalLOGV) Log.i(TAG, "starting " + showAdminSupportDetailsIntent); + startActivity(showAdminSupportDetailsIntent); + } else { + if (mLocalLOGV) Log.w(TAG, "not intent for " + restriction); + } + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java index 7e294eee024f..d1541569bc55 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java @@ -26,7 +26,6 @@ import android.app.AlertDialog; import android.app.AppOpsManager; import android.app.Dialog; import android.app.DialogFragment; -import android.app.admin.DevicePolicyManager; import android.content.ActivityNotFoundException; import android.content.ContentResolver; import android.content.Context; @@ -56,7 +55,6 @@ import android.widget.Button; import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.annotation.StringRes; import java.io.File; import java.util.ArrayList; @@ -123,13 +121,11 @@ public class PackageInstallerActivity extends AlertActivity { // Dialog identifiers used in showDialog private static final int DLG_BASE = 0; - private static final int DLG_PACKAGE_ERROR = DLG_BASE + 2; - private static final int DLG_OUT_OF_SPACE = DLG_BASE + 3; - private static final int DLG_INSTALL_ERROR = DLG_BASE + 4; - private static final int DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER = DLG_BASE + 5; - private static final int DLG_ANONYMOUS_SOURCE = DLG_BASE + 6; - private static final int DLG_EXTERNAL_SOURCE_BLOCKED = DLG_BASE + 7; - private static final int DLG_INSTALL_APPS_RESTRICTED_FOR_USER = DLG_BASE + 8; + private static final int DLG_PACKAGE_ERROR = DLG_BASE + 1; + private static final int DLG_OUT_OF_SPACE = DLG_BASE + 2; + private static final int DLG_INSTALL_ERROR = DLG_BASE + 3; + private static final int DLG_ANONYMOUS_SOURCE = DLG_BASE + 4; + private static final int DLG_EXTERNAL_SOURCE_BLOCKED = DLG_BASE + 5; // If unknown sources are temporary allowed private boolean mAllowUnknownSources; @@ -218,19 +214,13 @@ public class PackageInstallerActivity extends AlertActivity { if (mLocalLOGV) Log.i(TAG, "createDialog(" + id + ")"); switch (id) { case DLG_PACKAGE_ERROR: - return SimpleErrorDialog.newInstance(R.string.Parse_error_dlg_text); + return PackageUtil.SimpleErrorDialog.newInstance(R.string.Parse_error_dlg_text); case DLG_OUT_OF_SPACE: return OutOfSpaceDialog.newInstance( mPm.getApplicationLabel(mPkgInfo.applicationInfo)); case DLG_INSTALL_ERROR: return InstallErrorDialog.newInstance( mPm.getApplicationLabel(mPkgInfo.applicationInfo)); - case DLG_INSTALL_APPS_RESTRICTED_FOR_USER: - return SimpleErrorDialog.newInstance( - R.string.install_apps_user_restriction_dlg_text); - case DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER: - return SimpleErrorDialog.newInstance( - R.string.unknown_apps_user_restriction_dlg_text); case DLG_EXTERNAL_SOURCE_BLOCKED: return ExternalSourcesBlockedDialog.newInstance(mOriginatingPackage); case DLG_ANONYMOUS_SOURCE: @@ -524,67 +514,15 @@ public class PackageInstallerActivity extends AlertActivity { } /** - * Check if it is allowed to install the package and initiate install if allowed. If not allowed - * show the appropriate dialog. + * Check if it is allowed to install the package and initiate install if allowed. */ private void checkIfAllowedAndInitiateInstall() { - // Check for install apps user restriction first. - final int installAppsRestrictionSource = mUserManager.getUserRestrictionSource( - UserManager.DISALLOW_INSTALL_APPS, Process.myUserHandle()); - if ((installAppsRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) { - if (mLocalLOGV) Log.i(TAG, "install not allowed: " + UserManager.DISALLOW_INSTALL_APPS); - showDialogInner(DLG_INSTALL_APPS_RESTRICTED_FOR_USER); - return; - } else if (installAppsRestrictionSource != UserManager.RESTRICTION_NOT_SET) { - if (mLocalLOGV) { - Log.i(TAG, "install not allowed by admin; showing " - + Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS); - } - startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS)); - finish(); - return; - } - if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) { if (mLocalLOGV) Log.i(TAG, "install allowed"); initiateInstall(); } else { - // Check for unknown sources restrictions. - final int unknownSourcesRestrictionSource = mUserManager.getUserRestrictionSource( - UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, Process.myUserHandle()); - final int unknownSourcesGlobalRestrictionSource = mUserManager.getUserRestrictionSource( - UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, Process.myUserHandle()); - final int systemRestriction = UserManager.RESTRICTION_SOURCE_SYSTEM - & (unknownSourcesRestrictionSource | unknownSourcesGlobalRestrictionSource); - if (systemRestriction != 0) { - if (mLocalLOGV) Log.i(TAG, "Showing DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER"); - showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER); - } else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET) { - startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); - } else if (unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) { - startAdminSupportDetailsActivity( - UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY); - } else { - handleUnknownSources(); - } - } - } - - private void startAdminSupportDetailsActivity(String restriction) { - if (mLocalLOGV) Log.i(TAG, "startAdminSupportDetailsActivity(): " + restriction); - - // If the given restriction is set by an admin, display information about the - // admin enforcing the restriction for the affected user. - final DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class); - final Intent showAdminSupportDetailsIntent = dpm.createAdminSupportIntent(restriction); - if (showAdminSupportDetailsIntent != null) { - if (mLocalLOGV) Log.i(TAG, "starting " + showAdminSupportDetailsIntent); - startActivity(showAdminSupportDetailsIntent); - } else { - if (mLocalLOGV) Log.w(TAG, "not intent for " + restriction); + handleUnknownSources(); } - - finish(); } private void handleUnknownSources() { @@ -762,38 +700,6 @@ public class PackageInstallerActivity extends AlertActivity { } /** - * A simple error dialog showing a message - */ - public static class SimpleErrorDialog extends DialogFragment { - private static final String MESSAGE_KEY = - SimpleErrorDialog.class.getName() + "MESSAGE_KEY"; - - static SimpleErrorDialog newInstance(@StringRes int message) { - SimpleErrorDialog dialog = new SimpleErrorDialog(); - - Bundle args = new Bundle(); - args.putInt(MESSAGE_KEY, message); - dialog.setArguments(args); - - return dialog; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return new AlertDialog.Builder(getActivity()) - .setMessage(getArguments().getInt(MESSAGE_KEY)) - .setPositiveButton(R.string.ok, (dialog, which) -> getActivity().finish()) - .create(); - } - - @Override - public void onCancel(DialogInterface dialog) { - getActivity().setResult(Activity.RESULT_CANCELED); - getActivity().finish(); - } - } - - /** * Dialog to show when the source of apk can not be identified */ public static class AnonymousSourceDialog extends DialogFragment { diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java index 0270591acceb..ff0e5fb296b1 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java @@ -18,12 +18,17 @@ package com.android.packageinstaller; import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; import android.content.Context; +import android.content.DialogInterface; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.drawable.Drawable; +import android.os.Bundle; import android.os.UserHandle; import android.util.Log; import android.view.View; @@ -32,6 +37,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.StringRes; import java.io.Closeable; import java.io.File; @@ -207,4 +213,36 @@ public class PackageUtil { } } } + + /** + * A simple error dialog showing a message + */ + public static class SimpleErrorDialog extends DialogFragment { + private static final String MESSAGE_KEY = + SimpleErrorDialog.class.getName() + "MESSAGE_KEY"; + + static SimpleErrorDialog newInstance(@StringRes int message) { + SimpleErrorDialog dialog = new SimpleErrorDialog(); + + Bundle args = new Bundle(); + args.putInt(MESSAGE_KEY, message); + dialog.setArguments(args); + + return dialog; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + return new AlertDialog.Builder(getActivity()) + .setMessage(getArguments().getInt(MESSAGE_KEY)) + .setPositiveButton(R.string.ok, (dialog, which) -> getActivity().finish()) + .create(); + } + + @Override + public void onCancel(DialogInterface dialog) { + getActivity().setResult(Activity.RESULT_CANCELED); + getActivity().finish(); + } + } } |