Backport CTS for [Prevent shortcut info package name spoofing]
Test: cts-tradefed run cts -m CtsShortcutManagerTestCases -t android.content.pm.cts.shortcutmanager.ShortcutManagerFakingPublisherTest
Bug: 109824443
Bug: 111128116
Change-Id: Id754ac5a5d97122c06a119658bb65185b12c7d0b
Merged-In: I786c999982ae4861bf7c8a1c84507a0563c29b08
diff --git a/tests/tests/shortcutmanager/packages/packagemanifest_nonshared/AndroidManifest.xml b/tests/tests/shortcutmanager/packages/packagemanifest_nonshared/AndroidManifest.xml
index ee92b8c..bf3562b 100755
--- a/tests/tests/shortcutmanager/packages/packagemanifest_nonshared/AndroidManifest.xml
+++ b/tests/tests/shortcutmanager/packages/packagemanifest_nonshared/AndroidManifest.xml
@@ -21,6 +21,14 @@
<application>
<activity android:name="Launcher" android:enabled="true" android:exported="false">
</activity>
+
+ <activity-alias android:name="HomeActivity"
+ android:targetActivity="Launcher">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity-alias>
</application>
</manifest>
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java
index c0f76a6..99c7dc1 100644
--- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerClientApiTest.java
@@ -129,6 +129,8 @@
assertExpectException(NullPointerException.class, "action must be set",
() -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(new Intent()));
+ setCurrentCaller(getTestContext());
+
assertExpectException(
IllegalArgumentException.class, "Short label must be provided", () -> {
ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerFakingPublisherTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerFakingPublisherTest.java
new file mode 100644
index 0000000..baa47b0
--- /dev/null
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerFakingPublisherTest.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+package android.content.pm.cts.shortcutmanager;
+
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.runCommand;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ShortcutInfo;
+import android.platform.test.annotations.SecurityTest;
+import android.support.test.InstrumentationRegistry;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Assume;
+
+/**
+ * CTS for b/109824443.
+ */
+@SmallTest
+@SecurityTest
+public class ShortcutManagerFakingPublisherTest extends ShortcutManagerCtsTestsBase {
+ private static final String ANOTHER_PACKAGE =
+ "android.content.pm.cts.shortcutmanager.packages.package4";
+
+ private static final ComponentName ANOTHER_HOME_ACTIVITY = new ComponentName(
+ ANOTHER_PACKAGE, "android.content.pm.cts.shortcutmanager.packages.HomeActivity");
+
+ private static final String INVALID_ID =
+ "[ShortcutManagerFakingPublisherTest.shortcut_that_should_not_be_created]";
+
+ @Override
+ protected String getOverrideConfig() {
+ return "reset_interval_sec=999999,"
+ + "max_updates_per_interval=999999,"
+ + "max_shortcuts=10"
+ + "max_icon_dimension_dp=96,"
+ + "max_icon_dimension_dp_lowram=96,"
+ + "icon_format=PNG,"
+ + "icon_quality=100";
+ }
+
+ public void testSpoofingPublisher() {
+ final Context myContext = getTestContext();
+ final Context anotherContext;
+ try {
+ anotherContext = getTestContext().createPackageContext(ANOTHER_PACKAGE, 0);
+ } catch (NameNotFoundException e) {
+ fail("Unable to create package context for " + ANOTHER_PACKAGE);
+ return;
+ }
+ final ShortcutInfo invalid = new ShortcutInfo.Builder(anotherContext, INVALID_ID)
+ .setShortLabel(INVALID_ID)
+ .setIntent(new Intent(Intent.ACTION_VIEW))
+ .setActivity(ANOTHER_HOME_ACTIVITY)
+ .build();
+
+ // Check set.
+ runWithCaller(mPackageContext1, () -> {
+ getManager().removeAllDynamicShortcuts();
+
+ assertShortcutPackageMismatch("setDynamicShortcuts1", mPackageContext1, () -> {
+ getManager().setDynamicShortcuts(list(
+ invalid));
+ });
+ assertInvalidShortcutNotCreated();
+ assertShortcutPackageMismatch("setDynamicShortcuts2A", mPackageContext1, () -> {
+ getManager().setDynamicShortcuts(list(
+ invalid,
+ makeShortcut("s1", "title1")));
+ });
+ assertInvalidShortcutNotCreated();
+ assertShortcutPackageMismatch("setDynamicShortcuts2B", mPackageContext1, () -> {
+ getManager().setDynamicShortcuts(list(
+ makeShortcut("s1", "title1"),
+ invalid));
+ });
+ assertInvalidShortcutNotCreated();
+ });
+
+ // Check add.
+ runWithCaller(mPackageContext1, () -> {
+ getManager().removeAllDynamicShortcuts();
+
+ assertShortcutPackageMismatch("addDynamicShortcuts1", mPackageContext1, () -> {
+ getManager().addDynamicShortcuts(list(
+ invalid));
+ });
+ assertInvalidShortcutNotCreated();
+ assertShortcutPackageMismatch("addDynamicShortcuts2A", mPackageContext1, () -> {
+ getManager().addDynamicShortcuts(list(
+ invalid,
+ makeShortcut("s1", "title1")));
+ });
+ assertInvalidShortcutNotCreated();
+ assertShortcutPackageMismatch("addDynamicShortcuts2B", mPackageContext1, () -> {
+ getManager().addDynamicShortcuts(list(
+ makeShortcut("s1", "title1"),
+ invalid));
+ });
+ assertInvalidShortcutNotCreated();
+ });
+
+ // Check update.
+ runWithCaller(mPackageContext1, () -> {
+ getManager().removeAllDynamicShortcuts();
+
+ assertShortcutPackageMismatch("updateShortcuts1", mPackageContext1, () -> {
+ getManager().updateShortcuts(list(
+ invalid));
+ });
+ assertInvalidShortcutNotCreated();
+ assertShortcutPackageMismatch("updateShortcuts2A", mPackageContext1, () -> {
+ getManager().updateShortcuts(list(
+ invalid,
+ makeShortcut("s1", "title1")));
+ });
+ assertInvalidShortcutNotCreated();
+ assertShortcutPackageMismatch("updateShortcuts2B", mPackageContext1, () -> {
+ getManager().updateShortcuts(list(
+ makeShortcut("s1", "title1"),
+ invalid));
+ });
+ assertInvalidShortcutNotCreated();
+ });
+
+ // requestPin (API26 and above)
+ runWithCaller(mPackageContext1, () -> {
+ getManager().removeAllDynamicShortcuts();
+
+ assertShortcutPackageMismatch("requestPinShortcut", mPackageContext1, () -> {
+ getManager().requestPinShortcut(invalid, null);
+ });
+ assertInvalidShortcutNotCreated();
+ });
+
+ // createShortcutResultIntent (API26 and above)
+ runWithCaller(mPackageContext1, () -> {
+ getManager().removeAllDynamicShortcuts();
+
+ assertShortcutPackageMismatch("createShortcutResultIntent", mPackageContext1, () -> {
+ getManager().createShortcutResultIntent(invalid);
+ });
+ assertInvalidShortcutNotCreated();
+ });
+ }
+
+ private void assertInvalidShortcutNotCreated() {
+ for (String s : runCommand(InstrumentationRegistry.getInstrumentation(),
+ "dumpsys shortcut")) {
+ assertFalse("dumpsys shortcut contained invalid ID", s.contains(INVALID_ID));
+ }
+ }
+
+ private void assertShortcutPackageMismatch(String method, Context callerContext, Runnable r) {
+ assertExpectException(
+ "Caller=" + callerContext.getPackageName() + ", method=" + method,
+ SecurityException.class, "Shortcut package name mismatch",
+ () -> runWithCaller(callerContext, () -> r.run())
+ );
+ }
+}