Updated CTS test for Android Security b/143559931
Bug: 143559931
Bug: 202759784
Test: Ran the new testcase on android-10.0.0_r41 to test with/without patch
Change-Id: I7e261dbb566531e23cb46dc24f9986021219433b
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java
index 12287b0..95c90d4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -16,43 +16,39 @@
package android.security.cts;
-import android.platform.test.annotations.AppModeFull;
+import static org.junit.Assume.assumeNoException;
+
import android.platform.test.annotations.AsbSecurityTest;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
-import org.junit.Assert;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
public class CVE_2021_0954 extends StsExtraBusinessLogicHostTestBase {
- private static final String TEST_PKG = "android.security.cts.cve_2021_0954";
- private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
- private static final String TEST_APP = "CVE-2021-0954.apk";
- private ITestDevice device;
+ private static final String TEST_PKG = "android.security.cts.CVE_2021_0954";
- @Before
- public void setUp() throws Exception {
- device = getDevice();
- uninstallPackage(device, TEST_PKG);
-
- /* Wake up the screen */
- AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
- AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
- AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
- }
-
- @AppModeFull
@AsbSecurityTest(cveBugId = 143559931)
@Test
public void testPocCVE_2021_0954() throws Exception {
- installPackage(TEST_APP);
- AdbUtils.runCommandLine("pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW",
- device);
- runDeviceTests(TEST_PKG, TEST_CLASS, "testVulnerableActivityPresence");
+ try {
+ ITestDevice device = getDevice();
+ uninstallPackage(device, TEST_PKG);
+
+ /* Wake up the screen */
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ installPackage("CVE-2021-0954.apk");
+ AdbUtils.runCommandLine(
+ "pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW", device);
+ runDeviceTests(TEST_PKG, TEST_PKG + "." + "DeviceTest", "testOverlayButtonPresence");
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/Android.bp
index aa9f71f..59350cf 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/Android.bp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -18,10 +18,10 @@
android_test_helper_app {
name: "CVE-2021-0954",
defaults: ["cts_support_defaults"],
- srcs: ["src/**/*.java"],
+ srcs: [
+ "src/**/*.java"
+ ],
test_suites: [
- "cts",
- "vts10",
"sts",
],
static_libs: [
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/AndroidManifest.xml
index a7e0218..75299c4 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/AndroidManifest.xml
@@ -1,5 +1,5 @@
<!--
- Copyright 2021 The Android Open Source Project
+ Copyright 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.
@@ -13,25 +13,19 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="android.security.cts.cve_2021_0954"
+ package="android.security.cts.CVE_2021_0954"
android:versionCode="1"
android:versionName="1.0">
-
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
-
- <application
- android:allowBackup="true"
- android:label="CVE_2021_0954"
- android:supportsRtl="true">
- <uses-library android:name="android.test.runner" />
+ <application>
<service android:name=".PocService"
android:enabled="true"
- android:exported="false" />
+ android:exported="true" />
</application>
-
<instrumentation
android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.security.cts.cve_2021_0954" />
+ android:targetPackage="android.security.cts.CVE_2021_0954" />
</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/integers.xml
new file mode 100644
index 0000000..363df00
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/integers.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+ -->
+
+<resources>
+ <integer name="assumptionFailure">-1</integer>
+ <integer name="noAssumptionFailure">0</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/strings.xml
new file mode 100644
index 0000000..7c4d959
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/strings.xml
@@ -0,0 +1,38 @@
+<?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.
+-->
+
+<resources>
+ <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
+ <string name="defaultSemaphoreMsg">Could not get message key in shared preferences</string>
+ <string name="cmdDumpsysActivity">dumpsys activity %1$s</string>
+ <string name="empty"></string>
+ <string name="overlayErrorMessage">Device is vulnerable to b/143559931 hence any app with
+ "SYSTEM_ALERT_WINDOW can overlay the %1$s screen</string>
+ <string name="mResumedTrue">mResumed=true</string>
+ <string name="messageKey">message</string>
+ <string name="overlayButtonText">OverlayButton</string>
+ <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
+ <string name="resultKey">result</string>
+ <string name="sharedPreferences">CVE_2021_0954_prefs</string>
+ <string name="timedOutPocActivity">Timed out waiting on a result from PocActivity</string>
+ <string name="vulClass">com.android.internal.app.ResolverActivity</string>
+ <string name="vulClassAuto">com.android.car.activityresolver.CarResolverActivity</string>
+ <string name="vulPkg">android</string>
+ <string name="vulPkgAuto">com.android.car.activityresolver</string>
+ <string name="vulActivityNotRunningError">The %1$s is not currently running on the device
+ </string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/DeviceTest.java
index f986906..9a94ef9 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/DeviceTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -14,17 +14,20 @@
* limitations under the License.
*/
-package android.security.cts.cve_2021_0954;
+package android.security.cts.CVE_2021_0954;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assume.assumeNoException;
-import android.content.ActivityNotFoundException;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.pm.PackageManager;
import android.provider.Settings;
import androidx.test.runner.AndroidJUnit4;
@@ -32,90 +35,107 @@
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.Until;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.io.IOException;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
@RunWith(AndroidJUnit4.class)
public class DeviceTest {
- private static final String TEST_PKG = "android.security.cts.cve_2021_0954";
- private static final String TEST_VULNERABLE_PKG = "android";
- private static final String TEST_VULNERABLE_ACTIVITY =
- "com.android.internal.app.ResolverActivity";
- private static final int LAUNCH_TIMEOUT_MS = 20000;
- private static final String vulnerableActivityName = "ResolverActivity";
- private UiDevice mDevice;
- String activityDump = "";
+ private Context mContext = getApplicationContext();
+ private static final int TIMEOUT_MS = 10000;
- private void startOverlayService() {
- Context context = getApplicationContext();
- assertNotNull(context);
- Intent intent = new Intent(context, PocService.class);
- assertNotNull(intent);
-
- if (Settings.canDrawOverlays(getApplicationContext())) {
- context.startService(intent);
- } else {
- try {
- context.startService(intent);
- } catch (Exception e) {
- throw new RuntimeException("Unable to start the overlay service", e);
- }
- }
+ private boolean hasFeature(String feature) {
+ return mContext.getPackageManager().hasSystemFeature(feature);
}
- public void startVulnerableActivity() {
- Context context = getApplicationContext();
- Intent intent = new Intent();
- intent.setClassName(TEST_VULNERABLE_PKG, TEST_VULNERABLE_ACTIVITY);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- context.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- assumeNoException("Activity not found on device", e);
- }
+ private boolean isAuto() {
+ return hasFeature(PackageManager.FEATURE_AUTOMOTIVE);
}
- @Before
- public void setUp() throws Exception {
- mDevice = UiDevice.getInstance(getInstrumentation());
+ String getStringRes(int key) {
+ return mContext.getResources().getString(key);
+ }
- /* Start the vulnerable activity */
- startVulnerableActivity();
- if (!mDevice.wait(Until.hasObject(By.res("android:id/contentPanel")
- .clazz("android.widget.ScrollView").pkg("android")), LAUNCH_TIMEOUT_MS)) {
- return;
- }
+ String getStringResWithArg(int key, String arg) {
+ return mContext.getResources().getString(key, arg);
+ }
- /* Start the overlay service */
- startOverlayService();
+ int getIntegerRes(int key) {
+ return mContext.getResources().getInteger(key);
}
@Test
- public void testVulnerableActivityPresence() {
- Pattern overlayTextPattern = Pattern.compile("OverlayButton", Pattern.CASE_INSENSITIVE);
- if (!mDevice.wait(Until.hasObject(By.text(overlayTextPattern)), LAUNCH_TIMEOUT_MS)) {
- return;
- }
-
- /*
- * Check if the currently running activity is the vulnerable activity, if not abort the test
- */
+ public void testOverlayButtonPresence() {
try {
- activityDump = mDevice.executeShellCommand("dumpsys activity");
- } catch (IOException e) {
- throw new RuntimeException("Could not execute dumpsys activity command");
+ UiDevice device = UiDevice.getInstance(getInstrumentation());
+
+ /* Start the overlay service */
+ assumeTrue(getStringRes(R.string.canNotDrawOverlaysMsg),
+ Settings.canDrawOverlays(mContext));
+ Intent intent = new Intent(mContext, PocService.class);
+ mContext.startService(intent);
+
+ /* Wait for a result from overlay service */
+ SharedPreferences sharedPrefs = mContext.getSharedPreferences(
+ getStringRes(R.string.sharedPreferences), Context.MODE_PRIVATE);
+ final Semaphore preferenceChanged = new Semaphore(0);
+ OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+ String key) {
+ if (key.equals(getStringRes(R.string.resultKey))) {
+ preferenceChanged.release();
+ }
+ }
+ };
+ sharedPrefs.registerOnSharedPreferenceChangeListener(listener);
+ assumeTrue(preferenceChanged.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ int result = sharedPrefs.getInt(getStringRes(R.string.resultKey),
+ getIntegerRes(R.integer.assumptionFailure));
+ String message = sharedPrefs.getString(getStringRes(R.string.messageKey),
+ getStringRes(R.string.defaultSemaphoreMsg));
+ assumeTrue(message, result != getIntegerRes(R.integer.assumptionFailure));
+
+ /* Wait for the UI of overlay window to appear */
+ Pattern overlayTextPattern = Pattern.compile(
+ mContext.getString(R.string.overlayButtonText), Pattern.CASE_INSENSITIVE);
+ assumeTrue(mContext.getString(R.string.overlayUiScreenError),
+ device.wait(Until.hasObject(By.text(overlayTextPattern)), TIMEOUT_MS));
+
+ /* Start the vulnerable activity */
+ intent = new Intent();
+ String vulActivity = getStringRes(R.string.vulClass);
+ String vulPkg = getStringRes(R.string.vulPkg);
+ if (isAuto()) {
+ vulActivity = getStringRes(R.string.vulClassAuto);
+ vulPkg = getStringRes(R.string.vulPkgAuto);
+ }
+ intent.setClassName(vulPkg, vulActivity);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+
+ /* Wait until the object of overlay window is gone */
+ boolean overlayDisallowed =
+ device.wait(Until.gone(By.pkg(mContext.getPackageName())), TIMEOUT_MS);
+
+ /*
+ * Check if the currently running activity is the vulnerable activity, if not abort the
+ * test
+ */
+ String activityDump = device.executeShellCommand(
+ getStringResWithArg(R.string.cmdDumpsysActivity, vulActivity));
+ Pattern activityPattern = Pattern.compile(getStringRes(R.string.mResumedTrue));
+ assumeTrue(getStringRes(R.string.vulActivityNotRunningError),
+ activityPattern.matcher(activityDump).find());
+
+ /* Failing the test as fix is not present */
+ assertTrue(getStringResWithArg(R.string.overlayErrorMessage, vulActivity),
+ overlayDisallowed);
+ } catch (Exception e) {
+ assumeNoException(e);
}
- Pattern activityPattern =
- Pattern.compile("mResumedActivity.*" + vulnerableActivityName + ".*\n");
- if (!activityPattern.matcher(activityDump).find()) {
- return;
- }
- String message = "Device is vulnerable to b/143559931 hence any app with "
- + "SYSTEM_ALERT_WINDOW can overlay the ResolverActivity screen";
- assertNull(message, mDevice.findObject(By.text(overlayTextPattern)));
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/PocService.java
index 82b78a2..79270ba 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/PocService.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/PocService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -14,47 +14,65 @@
* limitations under the License.
*/
-package android.security.cts.cve_2021_0954;
+package android.security.cts.CVE_2021_0954;
import android.app.Service;
+import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.PixelFormat;
-import android.os.Handler;
import android.os.IBinder;
-import android.provider.Settings;
import android.view.Gravity;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.Button;
public class PocService extends Service {
- public static Button mButton;
- private WindowManager mWindowManager;
- private WindowManager.LayoutParams mLayoutParams;
+ Button mButton;
+ WindowManager mWindowManager;
- private static int getScreenWidth() {
+ private int getScreenWidth() {
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
- private static int getScreenHeight() {
+ private int getScreenHeight() {
return Resources.getSystem().getDisplayMetrics().heightPixels;
}
+ String getStringRes(int key) {
+ return getResources().getString(key);
+ }
+
+ int getIntegerRes(int key) {
+ return getResources().getInteger(key);
+ }
+
@Override
public void onCreate() {
- super.onCreate();
- mWindowManager = getSystemService(WindowManager.class);
- mLayoutParams = new WindowManager.LayoutParams();
- mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
- mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- mLayoutParams.format = PixelFormat.OPAQUE;
- mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
- mLayoutParams.width = getScreenWidth();
- mLayoutParams.height = getScreenHeight();
- mLayoutParams.x = getScreenWidth() / 2;
- mLayoutParams.y = getScreenHeight() / 2;
+ try {
+ super.onCreate();
+ mWindowManager = getSystemService(WindowManager.class);
+ LayoutParams layoutParams = new LayoutParams();
+ layoutParams.type = LayoutParams.TYPE_APPLICATION_OVERLAY;
+ layoutParams.flags =
+ LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE;
+ layoutParams.format = PixelFormat.OPAQUE;
+ layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
+ layoutParams.width = getScreenWidth();
+ layoutParams.height = getScreenHeight();
+ layoutParams.x = getScreenWidth() / 2;
+ layoutParams.y = getScreenHeight() / 2;
+
+ /* Show the floating window */
+ mButton = new Button(this);
+ mButton.setText(getString(R.string.overlayButtonText));
+ mWindowManager.addView(mButton, layoutParams);
+ } catch (Exception e) {
+ sendTestResult(getIntegerRes(R.integer.assumptionFailure), e.getMessage());
+ return;
+ }
+ sendTestResult(getIntegerRes(R.integer.noAssumptionFailure), getStringRes(R.string.empty));
}
@Override
@@ -63,31 +81,27 @@
}
@Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- showFloatingWindow();
- return super.onStartCommand(intent, flags, startId);
- }
-
- @Override
public void onDestroy() {
- if (mWindowManager != null && mButton != null) {
- mWindowManager.removeView(mButton);
+ try {
+ if (mWindowManager != null && mButton != null) {
+ mWindowManager.removeView(mButton);
+ }
+ super.onDestroy();
+ } catch (Exception e) {
+ sendTestResult(getIntegerRes(R.integer.assumptionFailure), e.getMessage());
}
- super.onDestroy();
}
- private void showFloatingWindow() {
- if (Settings.canDrawOverlays(this)) {
- mButton = new Button(getApplicationContext());
- mButton.setText("OverlayButton");
- mWindowManager.addView(mButton, mLayoutParams);
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- onDestroy();
- }
- }, 60000); // one minute
- mButton.setTag(mButton.getVisibility());
+ private void sendTestResult(int result, String message) {
+ try {
+ SharedPreferences sh = getSharedPreferences(getStringRes(R.string.sharedPreferences),
+ Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getStringRes(R.string.resultKey), result);
+ edit.putString(getStringRes(R.string.messageKey), message);
+ edit.commit();
+ } catch (Exception e) {
+ // ignore the exception
}
}
}