Fix cross user package visibility leakage for PackageManager (7/n)

For APIs:
- PackageManager#clearApplicationUserData
- PackageManager#getProperty
- PackageManager#getPermissionControllerPackageName
- PackageManager#setApplicationCategoryHint
- PackageManager#getUnsuspendablePackages
- PackageManager#setApplicationHiddenSettingAsUser

Bug: 229684723
Test: atest CrossUserPackageVisibilityTests
Change-Id: I70a20b4c41c870a160e808ee9707a6ec1a2da6e6
This commit is contained in:
Rhed Jao
2022-05-12 12:07:35 +08:00
parent 25a5ed69ee
commit 9d191fd7eb
6 changed files with 61 additions and 33 deletions

View File

@@ -387,12 +387,12 @@ public interface Computer extends PackageDataSnapshot {
String[] getSystemSharedLibraryNames();
/**
* @return the state if the given package has a state and isn't filtered by visibility.
* @return the state if the given package is installed and isn't filtered by visibility.
* Provides no guarantee that the package is in any usable state.
*/
@Nullable
PackageStateInternal getPackageStateFiltered(@NonNull String packageName, int callingUid,
@UserIdInt int userId);
PackageStateInternal getPackageStateForInstalledAndFiltered(@NonNull String packageName,
int callingUid, @UserIdInt int userId);
int checkSignatures(@NonNull String pkg1, @NonNull String pkg2, int userId);

View File

@@ -4238,10 +4238,11 @@ public class ComputerEngine implements Computer {
}
@Override
public PackageStateInternal getPackageStateFiltered(@NonNull String packageName, int callingUid,
@UserIdInt int userId) {
public PackageStateInternal getPackageStateForInstalledAndFiltered(@NonNull String packageName,
int callingUid, @UserIdInt int userId) {
final PackageStateInternal packageState = getPackageStateInternal(packageName);
if (packageState == null || shouldFilterApplication(packageState, callingUid, userId)) {
if (packageState == null
|| shouldFilterApplicationIncludingUninstalled(packageState, callingUid, userId)) {
return null;
}
return packageState;

View File

@@ -715,8 +715,8 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub {
String className) {
Objects.requireNonNull(propertyName);
Objects.requireNonNull(packageName);
PackageStateInternal packageState = snapshot().getPackageStateFiltered(packageName,
Binder.getCallingUid(), UserHandle.getCallingUserId());
PackageStateInternal packageState = snapshot().getPackageStateForInstalledAndFiltered(
packageName, Binder.getCallingUid(), UserHandle.getCallingUserId());
if (packageState == null) {
return null;
}

View File

@@ -4461,7 +4461,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
false /* checkShell */, "clear application data");
if (snapshot.getPackageStateFiltered(packageName, callingUid, userId) == null) {
if (snapshot.getPackageStateForInstalledAndFiltered(
packageName, callingUid, userId) == null) {
if (observer != null) {
mHandler.post(() -> {
try {
@@ -4918,9 +4919,10 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Override
public String getPermissionControllerPackageName() {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
final Computer snapshot = snapshotComputer();
if (snapshot.getPackageStateFiltered(mRequiredPermissionControllerPackage,
callingUid, UserHandle.getUserId(callingUid)) != null) {
if (snapshot.getPackageStateForInstalledAndFiltered(
mRequiredPermissionControllerPackage, callingUid, callingUserId) != null) {
return mRequiredPermissionControllerPackage;
}
@@ -4943,7 +4945,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
snapshot.enforceCrossUserPermission(
callingUid, userId, false /* requireFullPermission */,
false /* checkShell */, "getSplashScreenTheme");
PackageStateInternal packageState = filterPackageStateForInstalledAndFiltered(snapshot,
PackageStateInternal packageState = snapshot.getPackageStateForInstalledAndFiltered(
packageName, callingUid, userId);
return packageState == null ? null
: packageState.getUserStateOrDefault(userId).getSplashScreenTheme();
@@ -5350,8 +5352,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mInjector.getSystemService(AppOpsManager.class)
.checkPackage(Binder.getCallingUid(), callerPackageName);
PackageStateInternal packageState = computer.getPackageStateFiltered(packageName,
Binder.getCallingUid(), UserHandle.getCallingUserId());
PackageStateInternal packageState = computer.getPackageStateForInstalledAndFiltered(
packageName, Binder.getCallingUid(), UserHandle.getCallingUserId());
if (packageState == null) {
throw new IllegalArgumentException("Unknown target package " + packageName);
}
@@ -5420,7 +5422,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
final long callingId = Binder.clearCallingIdentity();
try {
final PackageStateInternal packageState =
snapshot.getPackageStateFiltered(packageName, callingUid, userId);
snapshot.getPackageStateForInstalledAndFiltered(
packageName, callingUid, userId);
if (packageState == null) {
return false;
}
@@ -5823,7 +5826,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
false /* checkShell */, "setSplashScreenTheme");
enforceOwnerRights(snapshot, packageName, callingUid);
PackageStateInternal packageState = filterPackageStateForInstalledAndFiltered(snapshot,
PackageStateInternal packageState = snapshot.getPackageStateForInstalledAndFiltered(
packageName, callingUid, userId);
if (packageState == null) {
return;
@@ -6395,7 +6398,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
public boolean registerInstalledLoadingProgressCallback(String packageName,
PackageManagerInternal.InstalledLoadingProgressCallback callback, int userId) {
final Computer snapshot = snapshotComputer();
final PackageStateInternal ps = filterPackageStateForInstalledAndFiltered(snapshot,
final PackageStateInternal ps = snapshot.getPackageStateForInstalledAndFiltered(
packageName, Binder.getCallingUid(), userId);
if (ps == null) {
return false;
@@ -6418,7 +6421,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
public IncrementalStatesInfo getIncrementalStatesInfo(
@NonNull String packageName, int filterCallingUid, int userId) {
final Computer snapshot = snapshotComputer();
final PackageStateInternal ps = filterPackageStateForInstalledAndFiltered(snapshot,
final PackageStateInternal ps = snapshot.getPackageStateForInstalledAndFiltered(
packageName, filterCallingUid, userId);
if (ps == null) {
return null;
@@ -6592,20 +6595,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService
return mSettings.getDisabledSystemPkgLPr(packageName);
}
@Nullable
private PackageStateInternal filterPackageStateForInstalledAndFiltered(
@NonNull Computer computer, @NonNull String packageName, int callingUid,
@UserIdInt int userId) {
PackageStateInternal packageState =
computer.getPackageStateInternal(packageName, callingUid);
if (computer.shouldFilterApplicationIncludingUninstalled(
packageState, callingUid, userId)) {
return null;
} else {
return packageState;
}
}
@Deprecated
void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
synchronized (mLock) {

View File

@@ -228,7 +228,8 @@ public final class SuspendPackageHelper {
continue;
}
final PackageStateInternal packageState =
snapshot.getPackageStateFiltered(packageNames[i], callingUid, userId);
snapshot.getPackageStateForInstalledAndFiltered(
packageNames[i], callingUid, userId);
if (packageState == null) {
Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]);
unactionablePackages.add(packageNames[i]);

View File

@@ -16,6 +16,8 @@
package com.android.server.pm.test.appenumeration;
import static android.Manifest.permission.CLEAR_APP_USER_DATA;
import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
import static com.google.common.truth.Truth.assertThat;
@@ -25,10 +27,12 @@ import static org.junit.Assert.assertThrows;
import android.app.AppGlobals;
import android.app.Instrumentation;
import android.content.Context;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageManager;
import android.content.pm.KeySet;
import android.content.pm.PackageManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -37,6 +41,7 @@ import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.EnsureHasSecondaryUser;
import com.android.bedstead.nene.users.UserReference;
import com.android.compatibility.common.util.TestUtils;
import org.junit.After;
import org.junit.Before;
@@ -46,6 +51,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Verify that app without holding the {@link android.Manifest.permission.INTERACT_ACROSS_USERS}
@@ -65,6 +71,8 @@ public class CrossUserPackageVisibilityTests {
private static final File SHARED_USER_TEST_APK_FILE =
new File(TEST_DATA_DIR, "AppEnumerationSharedUserTestApp.apk");
private static final long DEFAULT_TIMEOUT_MS = 5000;
@ClassRule
@Rule
public static final DeviceState sDeviceState = new DeviceState();
@@ -99,6 +107,7 @@ public class CrossUserPackageVisibilityTests {
public void tearDown() {
uninstallPackage(CROSS_USER_TEST_PACKAGE_NAME);
uninstallPackage(SHARED_USER_TEST_PACKAGE_NAME);
mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
}
@Test
@@ -184,6 +193,34 @@ public class CrossUserPackageVisibilityTests {
.isEqualTo(Process.INVALID_UID);
}
@Test
public void testClearApplicationUserData_cannotDetectStubPkg() throws Exception {
mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(CLEAR_APP_USER_DATA);
assertThat(clearApplicationUserData(CROSS_USER_TEST_PACKAGE_NAME)).isFalse();
installPackageForUser(CROSS_USER_TEST_APK_FILE, mOtherUser);
assertThat(clearApplicationUserData(CROSS_USER_TEST_PACKAGE_NAME)).isFalse();
}
private boolean clearApplicationUserData(String packageName) throws Exception {
final AtomicInteger result = new AtomicInteger(-1);
final IPackageDataObserver localObserver = new IPackageDataObserver.Stub() {
@Override
public void onRemoveCompleted(String removedPkgName, boolean succeeded)
throws RemoteException {
if (removedPkgName.equals(packageName)) {
result.set(succeeded ? 1 : 0);
result.notifyAll();
}
}
};
mIPackageManager.clearApplicationUserData(packageName, localObserver, mCurrentUser.id());
TestUtils.waitOn(result, () -> result.get() != -1, DEFAULT_TIMEOUT_MS,
"clearApplicationUserData: " + packageName);
return result.get() == 1;
}
private static void installPackage(File apk) {
installPackageForUser(apk, null, false /* forceQueryable */);
}