Fix cross user package visibility leakage for getAppOpPermissionPackages

To fix cross user package visibility leakage, this CL filters out
packages that aren't installed in the calling user before the API
returns results to the caller.

Also adding a user id parameter to the API for the system modules to
specify the correct user id when querying the appop permission packages.

NoNonSdkCheck: Keep @UnsupportedAppUsage for new signature api
Bug: 229684723
Test: atest CrossUserPackageVisibilityTests
Change-Id: I9d3de91b0195d3396d2737673cb23ef899e23467
This commit is contained in:
Rhed Jao
2022-05-26 15:00:46 +08:00
parent 6d8dfd0077
commit 8f7e68c0f4
9 changed files with 45 additions and 23 deletions

View File

@@ -110,7 +110,6 @@ Landroid/content/pm/IPackageInstallObserver2$Stub;-><init>()V
Landroid/content/pm/IPackageInstallObserver2$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageInstallObserver2;
Landroid/content/pm/IPackageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/pm/IPackageManager$Stub$Proxy;->checkUidPermission(Ljava/lang/String;I)I
Landroid/content/pm/IPackageManager$Stub$Proxy;->getAppOpPermissionPackages(Ljava/lang/String;)[Ljava/lang/String;
Landroid/content/pm/IPackageManager$Stub$Proxy;->getInstallLocation()I
Landroid/content/pm/IPackageManager$Stub$Proxy;->getLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;I)Landroid/content/pm/ResolveInfo;
Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackagesForUid(I)[Ljava/lang/String;

View File

@@ -746,7 +746,7 @@ interface IPackageManager {
// We need to keep these in IPackageManager for app compatibility
//------------------------------------------------------------------------
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
String[] getAppOpPermissionPackages(String permissionName);
String[] getAppOpPermissionPackages(String permissionName, int userId);
@UnsupportedAppUsage
PermissionGroupInfo getPermissionGroupInfo(String name, int flags);

View File

@@ -425,7 +425,7 @@ public interface Computer extends PackageDataSnapshot {
boolean isUidPrivileged(int uid);
@NonNull
String[] getAppOpPermissionPackages(@NonNull String permissionName);
String[] getAppOpPermissionPackages(@NonNull String permissionName, int userId);
@NonNull
ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(@NonNull String[] permissions,

View File

@@ -4699,22 +4699,21 @@ public class ComputerEngine implements Computer {
// NOTE: Can't remove due to unsupported app usage
@NonNull
@Override
public String[] getAppOpPermissionPackages(@NonNull String permissionName) {
if (permissionName == null) {
return EmptyArray.STRING;
}
public String[] getAppOpPermissionPackages(@NonNull String permissionName, int userId) {
final int callingUid = Binder.getCallingUid();
if (getInstantAppPackageName(callingUid) != null) {
enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
false /* checkShell */, "getAppOpPermissionPackages");
if (permissionName == null || getInstantAppPackageName(callingUid) != null
|| !mUserManager.exists(userId)) {
return EmptyArray.STRING;
}
final int callingUserId = UserHandle.getUserId(callingUid);
final ArraySet<String> packageNames = new ArraySet(
mPermissionManager.getAppOpPermissionPackages(permissionName));
for (int i = packageNames.size() - 1; i >= 0; i--) {
final String packageName = packageNames.valueAt(i);
if (!shouldFilterApplication(mSettings.getPackage(packageName), callingUid,
callingUserId)) {
if (!shouldFilterApplicationIncludingUninstalled(
mSettings.getPackage(packageName), callingUid, userId)) {
continue;
}
packageNames.removeAt(i);

View File

@@ -265,8 +265,9 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
}
private boolean canRequestInteractAcrossProfilesUnchecked(String packageName) {
final int callingUserId = mInjector.getCallingUserId();
final int[] enabledProfileIds =
mInjector.getUserManager().getEnabledProfileIds(mInjector.getCallingUserId());
mInjector.getUserManager().getEnabledProfileIds(callingUserId);
if (enabledProfileIds.length < 2) {
return false;
}
@@ -274,13 +275,14 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
return false;
}
return hasRequestedAppOpPermission(
AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName);
AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName,
callingUserId);
}
private boolean hasRequestedAppOpPermission(String permission, String packageName) {
private boolean hasRequestedAppOpPermission(String permission, String packageName, int userId) {
try {
String[] packages =
mInjector.getIPackageManager().getAppOpPermissionPackages(permission);
mInjector.getIPackageManager().getAppOpPermissionPackages(permission, userId);
return ArrayUtils.contains(packages, packageName);
} catch (RemoteException exc) {
Slog.e(TAG, "PackageManager dead. Cannot get permission info");
@@ -604,7 +606,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
return false;
}
if (!hasRequestedAppOpPermission(
AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName)) {
AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName, userId)) {
return false;
}
return isCrossProfilePackageAllowlisted(packageName);
@@ -627,7 +629,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
return false;
}
if (!hasRequestedAppOpPermission(
AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName)) {
AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName, userId)) {
return false;
}
return !isPlatformSignedAppWithNonUserConfigurablePermission(packageName, profileIds);

View File

@@ -324,8 +324,8 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub {
@NonNull
@Override
@Deprecated
public final String[] getAppOpPermissionPackages(@NonNull String permissionName) {
return snapshot().getAppOpPermissionPackages(permissionName);
public final String[] getAppOpPermissionPackages(@NonNull String permissionName, int userId) {
return snapshot().getAppOpPermissionPackages(permissionName, userId);
}
@Override

View File

@@ -171,7 +171,7 @@ public class CrossProfileAppsServiceImplRoboTest {
private void mockCrossProfileAppRequestsInteractAcrossProfiles() throws Exception {
final String permissionName = Manifest.permission.INTERACT_ACROSS_PROFILES;
when(mIPackageManager.getAppOpPermissionPackages(permissionName))
when(mIPackageManager.getAppOpPermissionPackages(eq(permissionName), anyInt()))
.thenReturn(new String[] {CROSS_PROFILE_APP_PACKAGE_NAME});
}
@@ -488,7 +488,7 @@ public class CrossProfileAppsServiceImplRoboTest {
private void mockCrossProfileAppDoesNotRequestInteractAcrossProfiles() throws Exception {
final String permissionName = Manifest.permission.INTERACT_ACROSS_PROFILES;
when(mIPackageManager.getAppOpPermissionPackages(permissionName))
when(mIPackageManager.getAppOpPermissionPackages(eq(permissionName), anyInt()))
.thenReturn(new String[] {});
}

View File

@@ -24,6 +24,7 @@ import android.app.AppGlobals;
import android.content.pm.IPackageManager;
import android.content.pm.ProviderInfo;
import android.os.Process;
import android.os.UserHandle;
import androidx.test.runner.AndroidJUnit4;
@@ -102,7 +103,7 @@ public class AppEnumerationInternalTests {
installPackage(HAS_APPOP_PERMISSION_APK_PATH, true /* forceQueryable */);
final String[] packageNames = mIPackageManager.getAppOpPermissionPackages(
PERMISSION_REQUEST_INSTALL_PACKAGES);
PERMISSION_REQUEST_INSTALL_PACKAGES, UserHandle.myUserId());
assertThat(packageNames).asList().contains(TARGET_HAS_APPOP_PERMISSION);
}
@@ -112,7 +113,7 @@ public class AppEnumerationInternalTests {
installPackage(HAS_APPOP_PERMISSION_APK_PATH, false /* forceQueryable */);
final String[] packageNames = mIPackageManager.getAppOpPermissionPackages(
PERMISSION_REQUEST_INSTALL_PACKAGES);
PERMISSION_REQUEST_INSTALL_PACKAGES, UserHandle.myUserId());
assertThat(packageNames).asList().doesNotContain(TARGET_HAS_APPOP_PERMISSION);
}

View File

@@ -73,13 +73,20 @@ public class CrossUserPackageVisibilityTests {
"com.android.appenumeration.crossuserpackagevisibility";
private static final String SHARED_USER_TEST_PACKAGE_NAME =
"com.android.appenumeration.shareduid";
private static final String HAS_APPOP_PERMISSION_PACKAGE_NAME =
"com.android.appenumeration.hasappoppermission";
private static final File CROSS_USER_TEST_APK_FILE =
new File(TEST_DATA_DIR, "AppEnumerationCrossUserPackageVisibilityTestApp.apk");
private static final File SHARED_USER_TEST_APK_FILE =
new File(TEST_DATA_DIR, "AppEnumerationSharedUserTestApp.apk");
private static final File HAS_APPOP_PERMISSION_APK_FILE =
new File(TEST_DATA_DIR, "AppEnumerationHasAppOpPermissionTestApp.apk");
private static final String ACTION_CROSS_USER_TEST =
"com.android.appenumeration.action.CROSS_USER_TEST";
private static final String PERMISSION_REQUEST_INSTALL_PACKAGES =
"android.permission.REQUEST_INSTALL_PACKAGES";
private static final ComponentName TEST_ACTIVITY_COMPONENT_NAME = new ComponentName(
CROSS_USER_TEST_PACKAGE_NAME, "com.android.appenumeration.testapp.DummyActivity");
@@ -264,6 +271,20 @@ public class CrossUserPackageVisibilityTests {
mCurrentUser.id())).isFalse();
}
@Test
public void testGetAppOpPermissionPackages_cannotDetectPkg() throws Exception {
final int userId = mCurrentUser.id();
assertThat(mIPackageManager
.getAppOpPermissionPackages(PERMISSION_REQUEST_INSTALL_PACKAGES, userId))
.asList().doesNotContain(HAS_APPOP_PERMISSION_PACKAGE_NAME);
installPackageForUser(HAS_APPOP_PERMISSION_APK_FILE, mOtherUser, true /* forceQueryable */);
assertThat(mIPackageManager
.getAppOpPermissionPackages(PERMISSION_REQUEST_INSTALL_PACKAGES, userId))
.asList().doesNotContain(HAS_APPOP_PERMISSION_PACKAGE_NAME);
}
private boolean clearApplicationUserData(String packageName) throws Exception {
final AtomicInteger result = new AtomicInteger(-1);
final IPackageDataObserver localObserver = new IPackageDataObserver.Stub() {