Fix cross user package visibility leakage for PackageManager (1/n)
APIs:
- IPackageManager#isPackageSignedByKeySet
- IPackageManager#isPackageSignedByKeySetExactly
Bug: 214394643
Test: atest CrossUserPackageVisibilityTests
Change-Id: I14e4cc5cf27f205353fe709bc2bc8b45778b0764
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index c5661a3..a29b1f8 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -5284,9 +5284,10 @@
return false;
}
final AndroidPackage pkg = mPackages.get(packageName);
+ final int callingUserId = UserHandle.getUserId(callingUid);
if (pkg == null
- || shouldFilterApplication(getPackageStateInternal(pkg.getPackageName()),
- callingUid, UserHandle.getUserId(callingUid))) {
+ || shouldFilterApplicationIncludingUninstalled(
+ getPackageStateInternal(pkg.getPackageName()), callingUid, callingUserId)) {
Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
@@ -5308,9 +5309,10 @@
return false;
}
final AndroidPackage pkg = mPackages.get(packageName);
+ final int callingUserId = UserHandle.getUserId(callingUid);
if (pkg == null
- || shouldFilterApplication(getPackageStateInternal(pkg.getPackageName()),
- callingUid, UserHandle.getUserId(callingUid))) {
+ || shouldFilterApplicationIncludingUninstalled(
+ getPackageStateInternal(pkg.getPackageName()), callingUid, callingUserId)) {
Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
index 479ef8e..cdb6324 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
+++ b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
@@ -30,6 +30,7 @@
"compatibility-device-util-axt",
"androidx.test.runner",
"truth-prebuilt",
+ "Harrier",
],
platform_apis: true,
test_suites: ["device-tests"],
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml b/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml
index 2039aaa..0395aa8 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml
+++ b/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml
@@ -16,7 +16,15 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.appenumeration">
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.server.pm.test.appenumeration">
+
+ <queries>
+ <package android:name="com.android.appenumeration.crossuserpackagevisibility" />
+ </queries>
+
+ <!-- It's merged from Harrier library. Remove it since this test should not hold it. -->
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:node="remove" />
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.server.pm.test.appenumeration"
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml b/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml
index 67efa14..f48974a 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml
+++ b/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml
@@ -34,6 +34,7 @@
<option name="push" value="AppEnumerationSyncProviderTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationSyncProviderTestApp.apk" />
<option name="push" value="AppEnumerationHasAppOpPermissionTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationHasAppOpPermissionTestApp.apk" />
<option name="push" value="AppEnumerationSharedUserTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationSharedUserTestApp.apk" />
+ <option name="push" value="AppEnumerationCrossUserPackageVisibilityTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationCrossUserPackageVisibilityTestApp.apk" />
</target_preparer>
<option name="test-tag" value="AppEnumerationInternalTest" />
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/CrossUserPackageVisibilityTests.java b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/CrossUserPackageVisibilityTests.java
index 3f6199c..437875b 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/CrossUserPackageVisibilityTests.java
+++ b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/CrossUserPackageVisibilityTests.java
@@ -16,30 +16,78 @@
package com.android.server.pm.test.appenumeration;
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertThrows;
import android.app.AppGlobals;
import android.app.Instrumentation;
+import android.content.Context;
import android.content.pm.IPackageManager;
+import android.content.pm.KeySet;
import android.os.UserHandle;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+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 org.junit.After;
import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-@RunWith(AndroidJUnit4.class)
+import java.io.File;
+
+/**
+ * Verify that app without holding the {@link android.Manifest.permission.INTERACT_ACROSS_USERS}
+ * can't detect the existence of another app in the different users on the device via the
+ * side channel attacks.
+ */
+@EnsureHasSecondaryUser
+@RunWith(BedsteadJUnit4.class)
public class CrossUserPackageVisibilityTests {
+ private static final String TEST_DATA_DIR = "/data/local/tmp/appenumerationtests";
+ private static final String CROSS_USER_TEST_PACKAGE_NAME =
+ "com.android.appenumeration.crossuserpackagevisibility";
+ private static final File CROSS_USER_TEST_APK_FILE =
+ new File(TEST_DATA_DIR, "AppEnumerationCrossUserPackageVisibilityTestApp.apk");
+
+ @ClassRule
+ @Rule
+ public static final DeviceState sDeviceState = new DeviceState();
private Instrumentation mInstrumentation;
private IPackageManager mIPackageManager;
+ private Context mContext;
+ private UserReference mOtherUser;
@Before
public void setup() {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mIPackageManager = AppGlobals.getPackageManager();
+ mContext = mInstrumentation.getContext();
+
+ // Get another user
+ final UserReference primaryUser = sDeviceState.primaryUser();
+ if (primaryUser.id() == UserHandle.myUserId()) {
+ mOtherUser = sDeviceState.secondaryUser();
+ } else {
+ mOtherUser = primaryUser;
+ }
+
+ uninstallPackage(CROSS_USER_TEST_PACKAGE_NAME);
+ }
+
+ @After
+ public void tearDown() {
+ uninstallPackage(CROSS_USER_TEST_PACKAGE_NAME);
}
@Test
@@ -49,4 +97,45 @@
() -> mIPackageManager.getSplashScreenTheme(
mInstrumentation.getContext().getPackageName(), crossUserId));
}
+
+ @Test
+ public void testIsPackageSignedByKeySet_cannotDetectCrossUserPkg() throws Exception {
+ final KeySet keySet = mIPackageManager.getSigningKeySet(mContext.getPackageName());
+ assertThrows(IllegalArgumentException.class,
+ () -> mIPackageManager.isPackageSignedByKeySet(
+ CROSS_USER_TEST_PACKAGE_NAME, keySet));
+
+ installPackageForUser(CROSS_USER_TEST_APK_FILE, mOtherUser);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mIPackageManager.isPackageSignedByKeySet(
+ CROSS_USER_TEST_PACKAGE_NAME, keySet));
+ }
+
+ @Test
+ public void testIsPackageSignedByKeySetExactly_cannotDetectCrossUserPkg() throws Exception {
+ final KeySet keySet = mIPackageManager.getSigningKeySet(mContext.getPackageName());
+ assertThrows(IllegalArgumentException.class,
+ () -> mIPackageManager.isPackageSignedByKeySetExactly(
+ CROSS_USER_TEST_PACKAGE_NAME, keySet));
+
+ installPackageForUser(CROSS_USER_TEST_APK_FILE, mOtherUser);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mIPackageManager.isPackageSignedByKeySetExactly(
+ CROSS_USER_TEST_PACKAGE_NAME, keySet));
+ }
+
+ private static void installPackageForUser(File apk, UserReference user) {
+ assertThat(apk.exists()).isTrue();
+ final StringBuilder cmd = new StringBuilder("pm install --user ");
+ cmd.append(user.id()).append(" ");
+ cmd.append(apk.getPath());
+ final String result = runShellCommand(cmd.toString());
+ assertThat(result.trim()).contains("Success");
+ }
+
+ private static void uninstallPackage(String packageName) {
+ runShellCommand("pm uninstall " + packageName);
+ }
}
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp
index e0f8327..9921106 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp
+++ b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp
@@ -62,3 +62,17 @@
test_suites: ["device-tests"],
platform_apis: true,
}
+
+android_test_helper_app {
+ name: "AppEnumerationCrossUserPackageVisibilityTestApp",
+ srcs: ["src/**/*.java"],
+ manifest: "AndroidManifest-crossUserPackageVisibility.xml",
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+ test_suites: ["device-tests"],
+ platform_apis: true,
+}
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-crossUserPackageVisibility.xml b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-crossUserPackageVisibility.xml
new file mode 100644
index 0000000..874a1fc
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-crossUserPackageVisibility.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.appenumeration.crossuserpackagevisibility">
+ <application>
+ </application>
+</manifest>