From 732edc3e39f1f068fb957a1e850182263a24b1f9 Mon Sep 17 00:00:00 2001 From: Suprabh Shukla Date: Fri, 31 May 2019 13:45:59 -0700 Subject: [PATCH] Kill uid when REQUEST_INSTALL_PACKAGES is denied Process privileges like open fds need to be revoked, when this permission is denied by the user. Test: Manually verified by checking logs. Robotest: atest SettingsRoboTests:ExternalSourcesDetailsTest Bug: 133504844 Change-Id: I81da0b3a5d6c54e392828829d1a2c43488439504 --- .../appinfo/ExternalSourcesDetails.java | 17 ++++++- .../appinfo/ExternalSourcesDetailsTest.java | 47 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java b/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java index b7232744365..fe1d81c17c1 100644 --- a/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java +++ b/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java @@ -18,6 +18,7 @@ package com.android.settings.applications.appinfo; import static android.app.Activity.RESULT_CANCELED; import static android.app.Activity.RESULT_OK; +import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.settings.SettingsEnums; import android.content.Context; @@ -29,6 +30,7 @@ import androidx.appcompat.app.AlertDialog; import androidx.preference.Preference; import androidx.preference.Preference.OnPreferenceChangeListener; +import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; import com.android.settings.Settings; import com.android.settings.applications.AppInfoWithHeader; @@ -44,6 +46,7 @@ public class ExternalSourcesDetails extends AppInfoWithHeader private AppStateInstallAppsBridge mAppBridge; private AppOpsManager mAppOpsManager; + private ActivityManager mActivityManager; private UserManager mUserManager; private RestrictedSwitchPreference mSwitchPref; private InstallAppsState mInstallAppsState; @@ -55,6 +58,7 @@ public class ExternalSourcesDetails extends AppInfoWithHeader final Context context = getActivity(); mAppBridge = new AppStateInstallAppsBridge(context, mState, null); mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + mActivityManager = context.getSystemService(ActivityManager.class); mUserManager = UserManager.get(context); addPreferencesFromResource(R.xml.external_sources_details); @@ -99,10 +103,21 @@ public class ExternalSourcesDetails extends AppInfoWithHeader : R.string.app_permission_summary_not_allowed); } - private void setCanInstallApps(boolean newState) { + @VisibleForTesting + void setCanInstallApps(boolean newState) { mAppOpsManager.setMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, mPackageInfo.applicationInfo.uid, mPackageName, newState ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_ERRORED); + if (!newState) { + killApp(mPackageInfo.applicationInfo.uid); + } + } + + private void killApp(int uid) { + if (UserHandle.isCore(uid)) { + return; + } + mActivityManager.killUid(uid, "User denied OP_REQUEST_INSTALL_PACKAGES"); } @Override diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/ExternalSourcesDetailsTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/ExternalSourcesDetailsTest.java index 10c2675be82..002a0bc5350 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/ExternalSourcesDetailsTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/ExternalSourcesDetailsTest.java @@ -19,11 +19,17 @@ package com.android.settings.applications.appinfo; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.ActivityManager; +import android.app.AppOpsManager; import android.content.Context; import android.content.ContextWrapper; import android.content.pm.ApplicationInfo; @@ -55,6 +61,10 @@ public class ExternalSourcesDetailsTest { @Mock private UserManager mUserManager; @Mock + private ActivityManager mActivityManager; + @Mock + private AppOpsManager mAppOpsManager; + @Mock private RestrictedSwitchPreference mSwitchPref; @Mock private RestrictedPreferenceHelper mHelper; @@ -69,9 +79,46 @@ public class ExternalSourcesDetailsTest { mFragment = new ExternalSourcesDetails(); ReflectionHelpers.setField(mFragment, "mUserManager", mUserManager); + ReflectionHelpers.setField(mFragment, "mActivityManager", mActivityManager); + ReflectionHelpers.setField(mFragment, "mAppOpsManager", mAppOpsManager); ReflectionHelpers.setField(mFragment, "mSwitchPref", mSwitchPref); } + @Test + public void setCanInstallApps_false_shouldKillNonCoreUid() { + int mockUid = 23456; + ReflectionHelpers.setField(mFragment, "mPackageInfo", mPackageInfo); + + mPackageInfo.applicationInfo = new ApplicationInfo(); + mPackageInfo.applicationInfo.uid = mockUid; + assertThat(UserHandle.isCore(mockUid)).isFalse(); + mFragment.setCanInstallApps(false); + verify(mActivityManager).killUid(eq(mockUid), anyString()); + } + + @Test + public void setCanInstallApps_false_shouldNotKillCoreUid() { + int mockUid = 1234; + ReflectionHelpers.setField(mFragment, "mPackageInfo", mPackageInfo); + + mPackageInfo.applicationInfo = new ApplicationInfo(); + mPackageInfo.applicationInfo.uid = mockUid; + assertThat(UserHandle.isCore(mockUid)).isTrue(); + mFragment.setCanInstallApps(false); + verify(mActivityManager, never()).killUid(eq(mockUid), anyString()); + } + + @Test + public void setCanInstallApps_true_shouldNotKillUid() { + int mockUid = 23456; + ReflectionHelpers.setField(mFragment, "mPackageInfo", mPackageInfo); + + mPackageInfo.applicationInfo = new ApplicationInfo(); + mPackageInfo.applicationInfo.uid = mockUid; + mFragment.setCanInstallApps(true); + verify(mActivityManager, never()).killUid(eq(mockUid), anyString()); + } + @Test public void refreshUi_noPackageInfo_shouldReturnFalseAndNoCrash() { mFragment.refreshUi();