diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-05-10 16:06:29 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-05-10 16:06:29 +0000 |
commit | 59e2afc31c6c2cba73bd6c6834db93c1c07e13ef (patch) | |
tree | 3996d3566992a0af741321bbb085681b84cf1552 | |
parent | 9684881f240024c3d5bf537f03eb74dbc8c237cc (diff) | |
parent | adbe4e46ae2b1c3143847055475d8310bc4ad0b5 (diff) | |
download | cts-android10-android13-mainline-tzdata-release.tar.gz |
Snap for 10101514 from adbe4e46ae2b1c3143847055475d8310bc4ad0b5 to qt-aml-tzdata-releaseq_tzdata_aml_296200000android10-android13-mainline-tzdata-release
Change-Id: I4bebde50c3f816ce6892886a51da109b9b932c30
67 files changed, 3545 insertions, 324 deletions
diff --git a/hostsidetests/appsecurity/Android.mk b/hostsidetests/appsecurity/Android.mk index da8b8799969..9fc24099e9e 100644 --- a/hostsidetests/appsecurity/Android.mk +++ b/hostsidetests/appsecurity/Android.mk @@ -21,7 +21,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_MODULE := CtsAppSecurityHostTestCases -LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util +LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util sts-host-util LOCAL_STATIC_JAVA_LIBRARIES := truth-prebuilt-jar diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/RoleSecurityTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/RoleSecurityTest.java index e86aa574897..2e182eb8349 100644 --- a/hostsidetests/appsecurity/src/android/appsecurity/cts/RoleSecurityTest.java +++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/RoleSecurityTest.java @@ -21,7 +21,7 @@ import android.platform.test.annotations.AsbSecurityTest; import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase; import static org.junit.Assert.assertNull; import static org.junit.Assume.assumeTrue; @@ -30,7 +30,7 @@ import org.junit.Test; import org.junit.runner.RunWith; @RunWith(DeviceJUnit4ClassRunner.class) -public class RoleSecurityTest extends BaseHostJUnit4Test { +public class RoleSecurityTest extends StsExtraBusinessLogicHostTestBase { private static final String ROLE_SECURITY_TEST_APP_APK = "CtsRoleSecurityTestApp.apk"; private static final String ROLE_SECURITY_TEST_APP_PACKAGE = "com.android.cts.rolesecuritytest"; diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0484/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0484/poc.cpp index a2e4ae58bfd..c06db765f0a 100644 --- a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0484/poc.cpp +++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0484/poc.cpp @@ -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,49 +18,37 @@ #include <media/mediaplayer.h> #include "../includes/common.h" -#define PREPARE_DRM 38 - using namespace android; int main() { + constexpr size_t bufferSize = 16; + constexpr uint32_t prepareDrm = 38; + constexpr uint32_t unknownTrxnCode = prepareDrm + 5; sp<IServiceManager> serviceManager = defaultServiceManager(); - if (serviceManager == nullptr) { - return EXIT_FAILURE; - } + FAIL_CHECK(serviceManager != nullptr); sp<IBinder> mediaPlayerService = serviceManager->getService(String16("media.player")); - if (mediaPlayerService == nullptr) { - return EXIT_FAILURE; - } + FAIL_CHECK(mediaPlayerService != nullptr); sp<IMediaPlayerService> iMediaPlayerService = IMediaPlayerService::asInterface(mediaPlayerService); - if (iMediaPlayerService == nullptr) { - return EXIT_FAILURE; - } + FAIL_CHECK(iMediaPlayerService != nullptr); - MediaPlayer *mediaPlayer = new MediaPlayer(); - if (mediaPlayer == nullptr) { - return EXIT_FAILURE; - } + sp<MediaPlayer> mediaPlayer = new MediaPlayer(); + FAIL_CHECK(mediaPlayer != nullptr); sp<IMediaPlayer> iMediaPlayer = iMediaPlayerService->create(mediaPlayer); - if (iMediaPlayer == nullptr) { - delete (mediaPlayer); - return EXIT_FAILURE; - } + FAIL_CHECK(iMediaPlayer != nullptr); Parcel data, reply; data.writeInterfaceToken(iMediaPlayer->getInterfaceDescriptor()); - const uint8_t arr[16] = {}; - data.write(arr, 16); - data.writeUint32(2); - data.writeUnpadded(arr, 1); - - IMediaPlayer::asBinder(iMediaPlayer)->transact(PREPARE_DRM, data, &reply); - uint32_t size = 0; - reply.readUint32(&size); - - delete (mediaPlayer); - return (size > 0) ? EXIT_VULNERABLE : EXIT_SUCCESS; + status_t status = IMediaPlayer::asBinder(iMediaPlayer)->transact(unknownTrxnCode, data, &reply); + FAIL_CHECK(status == UNKNOWN_TRANSACTION); + + const uint8_t arr[bufferSize] = {}; + data.write(arr, bufferSize); + data.writeUint32(bufferSize); + data.writeUnpadded(arr, bufferSize - 1); + status = IMediaPlayer::asBinder(iMediaPlayer)->transact(prepareDrm, data, &reply); + return status == OK ? EXIT_VULNERABLE : EXIT_SUCCESS; } diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java index 17b9b6a7d35..6289a52f39c 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java @@ -30,6 +30,11 @@ import com.android.sts.common.tradefed.testtype.SecurityTestCase; import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.log.LogUtil.CLog; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; @@ -40,13 +45,9 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Scanner; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; public class AdbUtils { @@ -60,6 +61,10 @@ public class AdbUtils { final static Pattern regexSpecialCharsEscapedPattern = Pattern.compile("[" + regexSpecialCharsEscaped + "]"); + /** + * @deprecated Use {@link NativePoc} instead. + */ + @Deprecated public static class pocConfig { String binaryName; String arguments; @@ -76,12 +81,15 @@ public class AdbUtils { } } - /** Runs a commandline on the specified device + /** + * Runs a commandline on the specified device * + * @deprecated Use {@link CommandUtil} instead. * @param command the command to be ran * @param device device for the command to be ran on * @return the console output from running the command */ + @Deprecated public static String runCommandLine(String command, ITestDevice device) throws Exception { if ("reboot".equals(command)) { throw new IllegalArgumentException( @@ -93,10 +101,12 @@ public class AdbUtils { /** * Pushes and runs a binary to the selected device * + * @deprecated Use {@link NativePoc} instead. * @param pocName name of the poc binary * @param device device to be ran on * @return the console output from the binary */ + @Deprecated public static String runPoc(String pocName, ITestDevice device) throws Exception { return runPoc(pocName, device, SecurityTestCase.TIMEOUT_NONDETERMINISTIC); } @@ -104,11 +114,13 @@ public class AdbUtils { /** * Pushes and runs a binary to the selected device * + * @deprecated Use {@link NativePoc} instead. * @param pocName name of the poc binary * @param device device to be ran on * @param timeout time to wait for output in seconds * @return the console output from the binary */ + @Deprecated public static String runPoc(String pocName, ITestDevice device, int timeout) throws Exception { return runPoc(pocName, device, timeout, null); } @@ -116,12 +128,14 @@ public class AdbUtils { /** * Pushes and runs a binary to the selected device * + * @deprecated Use {@link NativePoc} instead. * @param pocName name of the poc binary * @param device device to be ran on * @param timeout time to wait for output in seconds * @param arguments the input arguments for the poc * @return the console output from the binary */ + @Deprecated public static String runPoc(String pocName, ITestDevice device, int timeout, String arguments) throws Exception { CollectingOutputReceiver receiver = new CollectingOutputReceiver(); @@ -132,48 +146,57 @@ public class AdbUtils { /** * Pushes and runs a binary to the selected device and ignores any of its output. * + * @deprecated Use {@link NativePoc} instead. * @param pocName name of the poc binary * @param device device to be ran on * @param timeout time to wait for output in seconds */ + @Deprecated public static void runPocNoOutput(String pocName, ITestDevice device, int timeout) throws Exception { runPocNoOutput(pocName, device, timeout, null); } /** - * Pushes and runs a binary with arguments to the selected device and - * ignores any of its output. + * Pushes and runs a binary with arguments to the selected device and ignores any of its output. * + * @deprecated Use {@link NativePoc} instead. * @param pocName name of the poc binary * @param device device to be ran on * @param timeout time to wait for output in seconds * @param arguments input arguments for the poc */ - public static void runPocNoOutput(String pocName, ITestDevice device, int timeout, - String arguments) throws Exception { + @Deprecated + public static void runPocNoOutput( + String pocName, ITestDevice device, int timeout, String arguments) throws Exception { runPoc(pocName, device, timeout, arguments, null); } /** - * Pushes and runs a binary with arguments to the selected device and - * ignores any of its output. + * Pushes and runs a binary with arguments to the selected device and ignores any of its output. * + * @deprecated Use {@link NativePoc} instead. * @param pocName name of the poc binary * @param device device to be ran on * @param timeout time to wait for output in seconds * @param arguments input arguments for the poc * @param receiver the type of receiver to run against */ - public static int runPoc(String pocName, ITestDevice device, int timeout, - String arguments, IShellOutputReceiver receiver) throws Exception { + @Deprecated + public static int runPoc( + String pocName, + ITestDevice device, + int timeout, + String arguments, + IShellOutputReceiver receiver) + throws Exception { return runPoc(pocName, device, timeout, arguments, null, receiver); } /** - * Pushes and runs a binary with arguments to the selected device and - * ignores any of its output. + * Pushes and runs a binary with arguments to the selected device and ignores any of its output. * + * @deprecated Use {@link NativePoc} instead. * @param pocName name of the poc binary * @param device device to be ran on * @param timeout time to wait for output in seconds @@ -181,9 +204,15 @@ public class AdbUtils { * @param envVars run the poc with environment variables * @param receiver the type of receiver to run against */ - public static int runPoc(String pocName, ITestDevice device, int timeout, - String arguments, Map<String, String> envVars, - IShellOutputReceiver receiver) throws Exception { + @Deprecated + public static int runPoc( + String pocName, + ITestDevice device, + int timeout, + String arguments, + Map<String, String> envVars, + IShellOutputReceiver receiver) + throws Exception { String remoteFile = String.format("%s%s", TMP_PATH, pocName); SecurityTestCase.getPocPusher(device).pushFile(pocName, remoteFile); @@ -239,9 +268,12 @@ public class AdbUtils { /** * Assert the poc is executable + * + * @deprecated Use {@link NativePoc} instead. * @param pocName name of the poc binary * @param device device to be ran on */ + @Deprecated private static void assertPocExecutable(String pocName, ITestDevice device) throws Exception { String fullPocPath = TMP_PATH + pocName; device.executeShellCommand("chmod 777 " + fullPocPath); @@ -348,7 +380,10 @@ public class AdbUtils { } /** * Utility function to help check the exit code of a shell command + * + * @deprecated Use {@link CommandUtil} instead. */ + @Deprecated public static int runCommandGetExitCode(String cmd, ITestDevice device) throws Exception { long time = System.currentTimeMillis(); String exitStatusString = runCommandLine( @@ -370,16 +405,17 @@ public class AdbUtils { } /** - * Pushes and runs a binary to the selected device and checks exit code - * Return code 113 is used to indicate the vulnerability + * Pushes and runs a binary to the selected device and checks exit code Return code 113 is used + * to indicate the vulnerability * + * @deprecated Use {@link NativePoc} instead. * @param pocName a string path to poc from the /res folder * @param device device to be ran on * @param timeout time to wait for output in seconds */ @Deprecated - public static boolean runPocCheckExitCode(String pocName, ITestDevice device, - int timeout) throws Exception { + public static boolean runPocCheckExitCode(String pocName, ITestDevice device, int timeout) + throws Exception { //Refer to go/asdl-sts-guide Test section for knowing the significance of 113 code return runPocGetExitStatus(pocName, device, timeout) == 113; @@ -387,11 +423,13 @@ public class AdbUtils { /** * Pushes and runs a binary to the device and returns the exit status. + * + * @deprecated Use {@link NativePoc} instead. * @param pocName a string path to poc from the /res folder * @param device device to be ran on * @param timeout time to wait for output in seconds - */ + @Deprecated public static int runPocGetExitStatus(String pocName, ITestDevice device, int timeout) throws Exception { return runPocGetExitStatus(pocName, null, device, timeout); @@ -399,36 +437,49 @@ public class AdbUtils { /** * Pushes and runs a binary to the device and returns the exit status. + * + * @deprecated Use {@link NativePoc} instead. * @param pocName a string path to poc from the /res folder * @param arguments input arguments for the poc * @param device device to be ran on * @param timeout time to wait for output in seconds */ - public static int runPocGetExitStatus(String pocName, String arguments, ITestDevice device, - int timeout) throws Exception { + @Deprecated + public static int runPocGetExitStatus( + String pocName, String arguments, ITestDevice device, int timeout) throws Exception { return runPocGetExitStatus(pocName, arguments, null, device, timeout); } /** * Pushes and runs a binary to the device and returns the exit status. + * + * @deprecated Use {@link NativePoc} instead. * @param pocName name of the poc binary * @param arguments input arguments for the poc * @param envVars run the poc with environment variables * @param device device to be run on * @param timeout time to wait for output in seconds */ + @Deprecated public static int runPocGetExitStatus( - String pocName, String arguments, Map<String, String> envVars, - ITestDevice device, int timeout) throws Exception { + String pocName, + String arguments, + Map<String, String> envVars, + ITestDevice device, + int timeout) + throws Exception { return runPoc(pocName, device, timeout, arguments, envVars, null); } /** * Pushes and runs a binary and asserts that the exit status isn't 113: vulnerable. + * + * @deprecated Use {@link NativePoc} instead. * @param pocName a string path to poc from the /res folder * @param device device to be ran on * @param timeout time to wait for output in seconds */ + @Deprecated public static void runPocAssertExitStatusNotVulnerable( String pocName, ITestDevice device, int timeout) throws Exception { runPocAssertExitStatusNotVulnerable(pocName, null, device, timeout); @@ -436,27 +487,37 @@ public class AdbUtils { /** * Pushes and runs a binary and asserts that the exit status isn't 113: vulnerable. + * + * @deprecated Use {@link NativePoc} instead. * @param pocName a string path to poc from the /res folder * @param arguments input arguments for the poc * @param device device to be ran on * @param timeout time to wait for output in seconds */ - public static void runPocAssertExitStatusNotVulnerable(String pocName, String arguments, - ITestDevice device, int timeout) throws Exception { + @Deprecated + public static void runPocAssertExitStatusNotVulnerable( + String pocName, String arguments, ITestDevice device, int timeout) throws Exception { runPocAssertExitStatusNotVulnerable(pocName, arguments, null, device, timeout); } /** * Pushes and runs a binary and asserts that the exit status isn't 113: vulnerable. + * + * @deprecated Use {@link NativePoc} instead. * @param pocName name of the poc binary * @param arguments input arguments for the poc * @param envVars run the poc with environment variables * @param device device to be ran on * @param timeout time to wait for output in seconds */ + @Deprecated public static void runPocAssertExitStatusNotVulnerable( - String pocName, String arguments, Map<String, String> envVars, - ITestDevice device, int timeout) throws Exception { + String pocName, + String arguments, + Map<String, String> envVars, + ITestDevice device, + int timeout) + throws Exception { assertTrue("PoC returned exit status 113: vulnerable", runPocGetExitStatus(pocName, arguments, envVars, device, timeout) != 113); } @@ -496,12 +557,15 @@ public class AdbUtils { /** * Runs the poc binary and asserts that there are no security crashes that match the expected * process pattern. + * + * @deprecated Use {@link NativePoc} instead. * @param pocName a string path to poc from the /res folder * @param device device to be ran on * @param processPatternStrings a Pattern string to match the crash tombstone process */ - public static void runPocAssertNoCrashes(String pocName, ITestDevice device, - String... processPatternStrings) throws Exception { + @Deprecated + public static void runPocAssertNoCrashes( + String pocName, ITestDevice device, String... processPatternStrings) throws Exception { runPocAssertNoCrashes(pocName, device, new CrashUtils.Config().setProcessPatterns(processPatternStrings)); } @@ -509,25 +573,32 @@ public class AdbUtils { /** * Runs the poc binary and asserts that there are no security crashes that match the expected * process pattern. + * + * @deprecated Use {@link NativePoc} instead. * @param pocName a string path to poc from the /res folder * @param device device to be ran on * @param config a crash parser configuration */ - public static void runPocAssertNoCrashes(String pocName, ITestDevice device, - CrashUtils.Config config) throws Exception { + @Deprecated + public static void runPocAssertNoCrashes( + String pocName, ITestDevice device, CrashUtils.Config config) throws Exception { runPocAssertNoCrashes(pocName, device, null, config); } /** * Runs the poc binary and asserts that there are no security crashes that match the expected * process pattern, including arguments when running. + * + * @deprecated Use {@link NativePoc} instead. * @param pocName a string path to poc from the /res folder * @param device device to be ran on * @param arguments input arguments for the poc * @param config a crash parser configuration */ - public static void runPocAssertNoCrashes(String pocName, ITestDevice device, String arguments, - CrashUtils.Config config) throws Exception { + @Deprecated + public static void runPocAssertNoCrashes( + String pocName, ITestDevice device, String arguments, CrashUtils.Config config) + throws Exception { AdbUtils.runCommandLine("logcat -c", device); AdbUtils.runPocNoOutput(pocName, device, SecurityTestCase.TIMEOUT_NONDETERMINISTIC, arguments); @@ -535,97 +606,115 @@ public class AdbUtils { } /** - * Runs the poc binary and asserts following 2 conditions. - * 1. There are no security crashes in the binary. - * 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition). + * Runs the poc binary and asserts following 2 conditions. 1. There are no security crashes in + * the binary. 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability + * condition). * + * @deprecated Use {@link NativePoc} instead. * @param binaryName name of the binary * @param arguments arguments for running the binary * @param device device to be run on */ - public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments, - ITestDevice device) throws Exception { + @Deprecated + public static void runPocAssertNoCrashesNotVulnerable( + String binaryName, String arguments, ITestDevice device) throws Exception { runPocAssertNoCrashesNotVulnerable(binaryName, arguments, null, null, device, null); } /** - * Runs the poc binary and asserts following 2 conditions. - * 1. There are no security crashes in the binary. - * 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition). + * Runs the poc binary and asserts following 2 conditions. 1. There are no security crashes in + * the binary. 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability + * condition). * + * @deprecated Use {@link NativePoc} instead. * @param binaryName name of the binary * @param arguments arguments for running the binary * @param device device to be run on - * @param processPatternStrings a Pattern string to match the crash tombstone - * process + * @param processPatternStrings a Pattern string to match the crash tombstone process */ - public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments, - ITestDevice device, String processPatternStrings[]) throws Exception { + @Deprecated + public static void runPocAssertNoCrashesNotVulnerable( + String binaryName, String arguments, ITestDevice device, String processPatternStrings[]) + throws Exception { runPocAssertNoCrashesNotVulnerable(binaryName, arguments, null, null, device, processPatternStrings); } /** - * Runs the poc binary and asserts following 2 conditions. - * 1. There are no security crashes in the binary. - * 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition). + * Runs the poc binary and asserts following 2 conditions. 1. There are no security crashes in + * the binary. 2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability + * condition). * + * @deprecated Use {@link NativePoc} instead. * @param binaryName name of the binary * @param arguments arguments for running the binary * @param inputFiles files required as input - * @param inputFilesDestination destination directory to which input files are - * pushed + * @param inputFilesDestination destination directory to which input files are pushed * @param device device to be run on */ - public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments, - String inputFiles[], String inputFilesDestination, ITestDevice device) + @Deprecated + public static void runPocAssertNoCrashesNotVulnerable( + String binaryName, + String arguments, + String inputFiles[], + String inputFilesDestination, + ITestDevice device) throws Exception { runPocAssertNoCrashesNotVulnerable(binaryName, arguments, inputFiles, inputFilesDestination, device, null); } /** - * Runs the poc binary and asserts following 3 conditions. - * 1. There are no security crashes in the binary. - * 2. There are no security crashes that match the expected process pattern. - * 3. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition). + * Runs the poc binary and asserts following 3 conditions. 1. There are no security crashes in + * the binary. 2. There are no security crashes that match the expected process pattern. 3. The + * exit status isn't 113 (Code 113 is used to indicate the vulnerability condition). * + * @deprecated Use {@link NativePoc} instead. * @param binaryName name of the binary * @param arguments arguments for running the binary * @param inputFiles files required as input - * @param inputFilesDestination destination directory to which input files are - * pushed + * @param inputFilesDestination destination directory to which input files are pushed * @param device device to be run on - * @param processPatternStrings a Pattern string to match the crash tombstone - * process + * @param processPatternStrings a Pattern string to match the crash tombstone process */ - public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments, - String inputFiles[], String inputFilesDestination, ITestDevice device, - String processPatternStrings[]) throws Exception { + @Deprecated + public static void runPocAssertNoCrashesNotVulnerable( + String binaryName, + String arguments, + String inputFiles[], + String inputFilesDestination, + ITestDevice device, + String processPatternStrings[]) + throws Exception { runPocAssertNoCrashesNotVulnerable(binaryName, arguments, null, inputFiles, inputFilesDestination, device, processPatternStrings); } /** - * Runs the poc binary and asserts following 3 conditions. - * 1. There are no security crashes in the binary. - * 2. There are no security crashes that match the expected process pattern. - * 3. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition). + * Runs the poc binary and asserts following 3 conditions. 1. There are no security crashes in + * the binary. 2. There are no security crashes that match the expected process pattern. 3. The + * exit status isn't 113 (Code 113 is used to indicate the vulnerability condition). * + * @deprecated Use {@link NativePoc} instead. * @param binaryName name of the binary * @param arguments arguments for running the binary * @param envVars run the poc with environment variables * @param inputFiles files required as input - * @param inputFilesDestination destination directory to which input files are - * pushed + * @param inputFilesDestination destination directory to which input files are pushed * @param device device to be run on * @param processPatternStrings a Pattern string (other than binary name) to match the crash - * tombstone process + * tombstone process */ + @Deprecated public static void runPocAssertNoCrashesNotVulnerable( - String binaryName, String arguments, Map<String, String> envVars, - String inputFiles[], String inputFilesDestination, ITestDevice device, - String... processPatternStrings) throws Exception { + String binaryName, + String arguments, + Map<String, String> envVars, + String inputFiles[], + String inputFilesDestination, + ITestDevice device, + String... processPatternStrings) + throws Exception { pocConfig testConfig = new pocConfig(binaryName, device); testConfig.arguments = arguments; testConfig.envVars = envVars; @@ -649,13 +738,14 @@ public class AdbUtils { } /** - * Runs the poc binary and asserts following 3 conditions. - * 1. There are no security crashes in the binary. - * 2. There are no security crashes that match the expected process pattern. - * 3. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition). + * Runs the poc binary and asserts following 3 conditions. 1. There are no security crashes in + * the binary. 2. There are no security crashes that match the expected process pattern. 3. The + * exit status isn't 113 (Code 113 is used to indicate the vulnerability condition). * + * @deprecated Use {@link NativePoc} instead. * @param testConfig test configuration */ + @Deprecated public static void runPocAssertNoCrashesNotVulnerable(pocConfig testConfig) throws Exception { String[] inputFiles = null; if(!testConfig.inputFiles.isEmpty()) { @@ -689,11 +779,14 @@ public class AdbUtils { /** * Dumps logcat and asserts that there are no security crashes that match the expected process. - * By default, checks min crash addresses - * pattern. Ensure that adb logcat -c is called beforehand. + * By default, checks min crash addresses pattern. Ensure that adb logcat -c is called + * beforehand. + * + * @deprecated Use {@link TombstoneUtils} instead. * @param device device to be ran on * @param processPatternStrings a Pattern string to match the crash tombstone process */ + @Deprecated public static void assertNoCrashes(ITestDevice device, String... processPatternStrings) throws Exception { assertNoCrashes(device, new CrashUtils.Config().setProcessPatterns(processPatternStrings)); @@ -702,11 +795,14 @@ public class AdbUtils { /** * Dumps logcat and asserts that there are no security crashes that match the expected process * pattern. Ensure that adb logcat -c is called beforehand. + * * @param device device to be ran on * @param config a crash parser configuration + * @deprecated Use {@link TombstoneUtils} instead. */ - public static void assertNoCrashes(ITestDevice device, - CrashUtils.Config config) throws Exception { + @Deprecated + public static void assertNoCrashes(ITestDevice device, CrashUtils.Config config) + throws Exception { String logcat = AdbUtils.runCommandLine("logcat -d *:S DEBUG:V", device); JSONArray crashes = CrashUtils.addAllCrashes(logcat, new JSONArray()); diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_248251018.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_248251018.java new file mode 100644 index 00000000000..4b8389e7103 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_248251018.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 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.security.cts; + +import static org.junit.Assert.*; + +import android.platform.test.annotations.AsbSecurityTest; +import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class Bug_248251018 extends NonRootSecurityTestCase { + + @Test + @AsbSecurityTest(cveBugId = 248251018) + public void testEmergencyInfo_cannotInteractAcrossUsers() throws Exception { + String packageList = + getDevice() + .executeShellV2Command("pm list package com.android.emergency") + .getStdout(); + if (!packageList.isEmpty()) { + String result = + getDevice() + .executeShellV2Command("dumpsys package com.android.emergency") + .getStdout(); + assertFalse(result.contains("android.permission.INTERACT_ACROSS_USERS_FULL")); + } + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java index c98dc5e2153..c47c5bea32b 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.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. @@ -17,8 +17,10 @@ package android.security.cts; import android.platform.test.annotations.AsbSecurityTest; + import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + import org.junit.Test; import org.junit.runner.RunWith; @@ -28,12 +30,12 @@ public class CVE_2021_0484 extends NonRootSecurityTestCase { /** * b/173720767 * Vulnerability Behavior: EXIT_VULNERABLE (113) + * Vulnerable library : libmedia + * Is Play managed : No */ @Test @AsbSecurityTest(cveBugId = 173720767) public void testPocCVE_2021_0484() throws Exception { - AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2021-0484", getDevice()); - testConfig.checkCrash = false; - AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig); + AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2021-0484", getDevice(), 300); } } diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0963.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0963.java new file mode 100644 index 00000000000..90d8196c3f6 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0963.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package android.security.cts; + +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 org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2021_0963 extends StsExtraBusinessLogicHostTestBase { + static final String TEST_PKG = "android.security.cts.CVE_2021_0963"; + + /** + * b/199754277 + * Vulnerable app : KeyChain.apk + * Vulnerable module : com.android.keychain + * Is Play managed : No + */ + @AsbSecurityTest(cveBugId = 199754277) + @Test + public void testPocCVE_2021_0963() { + try { + ITestDevice device = getDevice(); + + /* Wake up the device */ + AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device); + AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device); + AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device); + + /* Install the application */ + installPackage("CVE-2021-0963.apk"); + + /* + * Set device as owner. After the test is completed, this change is reverted in the + * DeviceTest.java's tearDown() method by calling clearDeviceOwnerApp() on an instance + * of DevicePolicyManager. + */ + AdbUtils.runCommandLine("dpm set-device-owner --user 0 '" + TEST_PKG + "/" + TEST_PKG + + ".PocDeviceAdminReceiver" + "'", device); + + /* Run the device test "testOverlayButtonPresence" */ + runDeviceTests(TEST_PKG, TEST_PKG + "." + "DeviceTest", "testOverlayButtonPresence"); + } catch (Exception e) { + assumeNoException(e); + } + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20112.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20112.java new file mode 100644 index 00000000000..cc9d347c8f7 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20112.java @@ -0,0 +1,88 @@ +/* + * 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. + */ + +package android.security.cts; + +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; + +import android.platform.test.annotations.AsbSecurityTest; + +import com.android.sts.common.tradefed.testtype.RootSecurityTestCase; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2022_20112 extends RootSecurityTestCase { + + // b/206987762 + // Vulnerable module : com.android.settings + // Vulnerable apk : Settings.apk + // Is play managed : No + @AsbSecurityTest(cveBugId = 206987762) + @Test + public void testPocCVE_2022_20112() { + final String testPkg = "android.security.cts.CVE_2022_20112"; + ITestDevice device = null; + int currentUser = -1; + int newUser = -1; + try { + device = getDevice(); + + // Device wakeup and unlock + AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device); + AdbUtils.runCommandLine("wm dismiss-keyguard", device); + + // Get current user + currentUser = device.getCurrentUser(); + + // Create new guest user 'CTSUser' for test + newUser = device.createUser("CTSUser", true, false); + + // Start new guest user 'CTSUser' + assumeTrue("Unable to create new guest user", device.startUser(newUser, true)); + + // Switch to new user 'CTSUser' + assumeTrue("Unable to switch to guest user", device.switchUser(newUser)); + + // Install PoC application + installPackage("CVE-2022-20112.apk"); + + runDeviceTests(testPkg, testPkg + ".DeviceTest", "testprivateDnsPreferenceController"); + } catch (Exception e) { + assumeNoException(e); + } finally { + try { + if (currentUser != -1) { + // Switch back to previous user + device.switchUser(currentUser); + } + if (newUser != -1) { + // Stop user 'CTSUser' + device.stopUser(newUser); + + // Remove user 'CTSUser' + device.removeUser(newUser); + } + } catch (Exception e) { + // Ignore exception here + } + } + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java index 3d31cee17c7..98befd4884a 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java @@ -16,18 +16,18 @@ package android.security.cts; +import static com.android.sts.common.SystemUtil.withSetting; + import static org.junit.Assume.assumeNoException; import android.platform.test.annotations.AsbSecurityTest; import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase; -import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import org.junit.Test; import org.junit.runner.RunWith; - @RunWith(DeviceJUnit4ClassRunner.class) public class CVE_2022_20197 extends NonRootSecurityTestCase { private static final String TEST_PKG = "android.security.cts.CVE_2022_20197"; @@ -35,37 +35,11 @@ public class CVE_2022_20197 extends NonRootSecurityTestCase { @AsbSecurityTest(cveBugId = 208279300) @Test public void testPocCVE_2022_20197() { - ITestDevice device = null; - boolean isPolicyPresent = true; - boolean isHiddenApiEnabled = true; - String status = ""; - try { - device = getDevice(); + try (AutoCloseable a = withSetting(getDevice(), "global", "hidden_api_policy", "1")) { installPackage("CVE-2022-20197.apk"); - - status = AdbUtils.runCommandLine("settings get global hidden_api_policy", device); - if (status.toLowerCase().contains("null")) { - isPolicyPresent = false; - } else if (!status.toLowerCase().contains("1")) { - isHiddenApiEnabled = false; - } - if (!isPolicyPresent || !isHiddenApiEnabled) { - AdbUtils.runCommandLine("settings put global hidden_api_policy 1", device); - } runDeviceTests(TEST_PKG, TEST_PKG + ".DeviceTest", "testParcel"); } catch (Exception e) { assumeNoException(e); - } finally { - try { - if (!isPolicyPresent) { - AdbUtils.runCommandLine("settings delete global hidden_api_policy", device); - } else if (!isHiddenApiEnabled) { - AdbUtils.runCommandLine("settings put global hidden_api_policy " + status, - device); - } - } catch (Exception e) { - // ignore all exceptions. - } } } } diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20360.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20360.java new file mode 100644 index 00000000000..0568740ce20 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20360.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package android.security.cts; + +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; + +import android.platform.test.annotations.AsbSecurityTest; + +import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2022_20360 extends NonRootSecurityTestCase { + + // b/228314987 + // Vulnerable apk : Settings.apk + // Vulnerable module : com.android.settings + // Is Play managed : No + @AsbSecurityTest(cveBugId = 228314987) + @Test + public void testPocCVE_2022_20360() { + final String testPkg = "android.security.cts.CVE_2022_20360"; + ITestDevice device = null; + int currentUser = -1; + int newUser = -1; + try { + device = getDevice(); + + // Check if device supports nfc + assumeTrue("Device does not support nfc", device.hasFeature("android.hardware.nfc")); + + // Get current user + currentUser = device.getCurrentUser(); + + // Create new guest user 'CTSUser' for test + newUser = device.createUser("CTSUser", true, false); + + // Start new guest user 'CTSUser' + assumeTrue("Unable to create new guest user", device.startUser(newUser, true)); + + // Switch to new user 'CTSUser' + assumeTrue("Unable to switch to guest user", device.switchUser(newUser)); + + // Install test-app + installPackage("CVE-2022-20360.apk", "--user " + newUser); + + runDeviceTests(testPkg, testPkg + ".DeviceTest", "testSecureNfcPreferenceController"); + } catch (Exception e) { + assumeNoException(e); + } finally { + try { + if (currentUser != -1) { + // Switch back to previous user + device.switchUser(currentUser); + } + if (newUser != -1) { + // Stop user 'CTSUser' + device.stopUser(newUser); + + // Remove user 'CTSUser' + device.removeUser(newUser); + } + } catch (Exception e) { + // Ignore exception here + } + } + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20415.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20415.java new file mode 100644 index 00000000000..511cbd4ac45 --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20415.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 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.security.cts; + +import static org.junit.Assume.assumeNoException; + +import android.platform.test.annotations.AsbSecurityTest; + +import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2022_20415 extends NonRootSecurityTestCase { + + // b/231322873 + // Vulnerable app : SystemUI.apk + // Vulnerable module : com.android.systemui + // Is Play managed : No + @AsbSecurityTest(cveBugId = 231322873) + @Test + public void testPocCVE_2022_20415() { + try { + final String testPkg = "android.security.cts.CVE_2022_20415"; + + // Install the test-app + installPackage("CVE-2022-20415.apk"); + runDeviceTests(testPkg, testPkg + "." + "DeviceTest", "testFullScreenIntent"); + } catch (Exception e) { + assumeNoException(e); + } + } +} diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20913.java index 2e1ddda5360..5e4da6900af 100644 --- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20913.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,41 +16,37 @@ 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.NonRootSecurityTestCase; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(DeviceJUnit4ClassRunner.class) -public class CVE_2021_0642 extends NonRootSecurityTestCase { - static final String TEST_APP = "CVE-2021-0642.apk"; - static final String TEST_PKG = "android.security.cts.cve_2021_0642"; - static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest"; - - @Before - public void setUp() throws Exception { - ITestDevice device = getDevice(); - AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device); - AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device); - AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device); - uninstallPackage(device, TEST_PKG); - } +public class CVE_2023_20913 extends NonRootSecurityTestCase { - /** - * b/185126149 - */ - @AppModeFull - @AsbSecurityTest(cveBugId = 185126149) + // b/246933785 + // Vulnerable app : Telephony.apk + // Vulnerable module : com.android.phone + // Is Play managed : No + @AsbSecurityTest(cveBugId = 246933785) @Test - public void testPocCVE_2021_0642() throws Exception { - installPackage(TEST_APP); - Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testCVE_2021_0642")); + public void testPocCVE_2023_20913() { + try { + final String testPkg = "android.security.cts.CVE_2023_20913"; + ITestDevice device = getDevice(); + installPackage("CVE-2023-20913.apk"); + + AdbUtils.runCommandLine( + "pm grant " + testPkg + " android.permission.SYSTEM_ALERT_WINDOW", device); + runDeviceTests(testPkg, testPkg + ".DeviceTest", "testOverlayButtonPresence"); + } catch (Exception e) { + assumeNoException(e); + } } } diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20918.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20918.java new file mode 100644 index 00000000000..659c002d83f --- /dev/null +++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20918.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +package android.security.cts; + +import static org.junit.Assume.assumeNoException; + +import android.platform.test.annotations.AsbSecurityTest; + +import com.android.sts.common.SystemUtil; +import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class CVE_2023_20918 extends NonRootSecurityTestCase { + + // b/243794108 + // Vulnerable library : services.jar + // Vulnerable module : Not applicable + // Is Play Managed : No + @AsbSecurityTest(cveBugId = 243794108) + @Test + public void testPocCVE_2023_20918() { + try { + final String testPkg = "android.security.cts.CVE_2023_20918_test"; + + // Install the test and attacker apps + installPackage("CVE-2023-20918-test.apk"); + installPackage("CVE-2023-20918-attacker.apk"); + + // Allow access to hidden api "ActivityOptions#setPendingIntentLaunchFlags()" + try (AutoCloseable closable = + SystemUtil.withSetting(getDevice(), "global", "hidden_api_policy", "1")) { + // Run the test "testCVE_2023_20918" + runDeviceTests(testPkg, testPkg + ".DeviceTest", "testCVE_2023_20918"); + } + } catch (Exception e) { + assumeNoException(e); + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/DeviceTest.java deleted file mode 100644 index 8fc235ba9da..00000000000 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/DeviceTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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. - */ - -package android.security.cts.cve_2021_0642; - -import static androidx.test.core.app.ApplicationProvider.getApplicationContext; -import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeNoException; -import static org.junit.Assume.assumeTrue; - -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.telephony.TelephonyManager; - -import androidx.test.runner.AndroidJUnit4; -import androidx.test.uiautomator.By; -import androidx.test.uiautomator.BySelector; -import androidx.test.uiautomator.UiDevice; -import androidx.test.uiautomator.UiObject2; -import androidx.test.uiautomator.Until; - -import java.util.List; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class DeviceTest { - static final String APP_TITLE = "CVE-2021-0642"; - static final String PACKAGE_NAME = "com.android.phone"; - static final int LAUNCH_TIMEOUT_MS = 20000; - - @Test - public void testCVE_2021_0642() { - UiDevice device = UiDevice.getInstance(getInstrumentation()); - Context context = getApplicationContext(); - assertThat(context, notNullValue()); - PackageManager packageManager = context.getPackageManager(); - assertThat(packageManager, notNullValue()); - assumeTrue(packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)); - final Intent intent = new Intent(TelephonyManager.ACTION_CONFIGURE_VOICEMAIL); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - context.startActivity(intent); - } catch (ActivityNotFoundException e) { - assumeNoException(e); - } - - // Check if "com.android.phone" exists on the system - try { - packageManager.getPackageUid(PACKAGE_NAME, 0); - } catch (PackageManager.NameNotFoundException e) { - assumeNoException(e); - } - - // Wait for activity (which is part of package "com.android.phone") that - // handles ACTION_CONFIGURE_VOICEMAIL to get launched - boolean isVoicemailVisible = - device.wait(Until.hasObject(By.pkg(PACKAGE_NAME)), LAUNCH_TIMEOUT_MS); - - // To check if PocActivity was launched - BySelector selector = By.enabled(true); - List<UiObject2> objects = device.findObjects(selector); - boolean isPocActivityVisible = false; - for (UiObject2 o : objects) { - String visibleText = o.getText(); - if ((visibleText != null) && (visibleText.equalsIgnoreCase(APP_TITLE))) { - isPocActivityVisible = true; - break; - } - } - device.pressHome(); - - assumeTrue(isVoicemailVisible || isPocActivityVisible); - - String outputMsg = "Device is vulnerable to b/185126149 " - + "hence sensitive Iccid could be sniffed by intercepting " - + "ACTION_CONFIGURE_VOICEMAIL implicit intent"; - assertTrue(outputMsg, ((isVoicemailVisible) && (!isPocActivityVisible))); - } -} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/Android.bp new file mode 100644 index 00000000000..ea39e68b2be --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/Android.bp @@ -0,0 +1,39 @@ +/* + * 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. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2021-0963", + defaults: [ + "cts_defaults", + ], + srcs: [ + "src/**/*.java", + ], + test_suites: [ + "sts", + ], + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + "androidx.test.uiautomator_uiautomator", + ], + platform_apis: true, +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/AndroidManifest.xml index fadda577403..ae0d4160fcb 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/AndroidManifest.xml +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/AndroidManifest.xml @@ -14,31 +14,29 @@ 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="android.security.cts.cve_2021_0642" - android:versionCode="1" - android:versionName="1.0"> - <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> - <application - android:allowBackup="true" - android:label="CVE-2021-0642" - android:supportsRtl="true"> - <activity - android:name=".PocActivity" +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.security.cts.CVE_2021_0963"> + <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> + <application> + <activity android:name=".PocActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> + </activity> + <receiver android:name=".PocDeviceAdminReceiver" + android:exported="true" + android:permission="android.permission.BIND_DEVICE_ADMIN"> + <meta-data android:name="android.app.device_admin" + android:resource="@xml/device_policies" /> <intent-filter> - <action android:name="android.telephony.action.CONFIGURE_VOICEMAIL" /> - <category android:name="android.intent.category.DEFAULT" /> + <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> </intent-filter> - </activity> + </receiver> + <service android:name=".PocService" /> </application> - - <instrumentation - android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="android.security.cts.cve_2021_0642" /> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.CVE_2021_0963" /> </manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/integers.xml index 7460b96ae6b..6a14b4a8240 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/res/layout/activity_main.xml +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/integers.xml @@ -14,13 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. --> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <View - android:id="@+id/drawableview" - android:layout_width="match_parent" - android:layout_height="300dp" /> -</LinearLayout> + +<resources> + <integer name="assumptionFailure">-1</integer> + <integer name="noException">0</integer> + <integer name="timeoutMs">10000</integer> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/strings.xml new file mode 100644 index 00000000000..1da84fe3711 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/strings.xml @@ -0,0 +1,40 @@ +<?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> + <string name="actionKeychainActivity">com.android.keychain.CHOOSER</string> + <string name="activityNotFoundMsg">The activity with intent was not found : </string> + <string name="activityNotStartedException">Unable to start the activity with intent : </string> + <string name="alias">Client</string> + <string name="callbackKey">callback</string> + <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string> + <string name="certType">X.509</string> + <string name="dumpsysActivity">dumpsys activity %1$s</string> + <string name="dumpsysActivityNotStartedException">Could not execute dumpsys activity command + </string> + <string name="errorMessage">Device is vulnerable to b/199754277 hence any app with + "SYSTEM_ALERT_WINDOW can overlay the %1$s screen</string> + <string name="keyType">RSA</string> + <string name="mResumedTrue">mResumed=true</string> + <string name="messageKey">message</string> + <string name="overlayButtonText">OverlayButton</string> + <string name="overlayServiceNotStartedException">Unable to start the overlay service</string> + <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string> + <string name="statusKey">status</string> + <string name="vulActivityNotRunningError">The activity %1$s is not currently running + on the device</string> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/xml/device_policies.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/xml/device_policies.xml new file mode 100644 index 00000000000..a826e80f531 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/xml/device_policies.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. + --> + +<device-admin> + <uses-policies> + </uses-policies> +</device-admin> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/DeviceTest.java new file mode 100644 index 00000000000..3d1c0df2131 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/DeviceTest.java @@ -0,0 +1,401 @@ +/* + * 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. + */ + +package android.security.cts.CVE_2021_0963; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; + +import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.res.Resources; +import android.os.Bundle; +import android.os.RemoteCallback; +import android.provider.Settings; + +import androidx.test.runner.AndroidJUnit4; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.Until; + +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.ByteArrayInputStream; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + private DevicePolicyManager mDevicePolicyManager; + private ComponentName mComponentName; + Context mContext; + + /** + * Generated from above and converted with: + * + * openssl pkcs8 -topk8 -outform d -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g' + */ + private static final byte[] PRIVATE_KEY = + new byte[] {(byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x76, (byte) 0x02, + (byte) 0x01, (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, + (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, + (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, + (byte) 0x82, (byte) 0x02, (byte) 0x60, (byte) 0x30, (byte) 0x82, (byte) 0x02, + (byte) 0x5c, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81, + (byte) 0x81, (byte) 0x00, (byte) 0xee, (byte) 0x6e, (byte) 0x51, (byte) 0xa8, + (byte) 0xc4, (byte) 0x44, (byte) 0xd9, (byte) 0xb7, (byte) 0x53, (byte) 0xf1, + (byte) 0xb9, (byte) 0x1b, (byte) 0x9d, (byte) 0x8d, (byte) 0x7c, (byte) 0x9f, + (byte) 0x06, (byte) 0xe7, (byte) 0xed, (byte) 0xa8, (byte) 0x05, (byte) 0xb8, + (byte) 0xaa, (byte) 0x0a, (byte) 0x2d, (byte) 0x74, (byte) 0x05, (byte) 0x8b, + (byte) 0xad, (byte) 0xfe, (byte) 0xd3, (byte) 0x3e, (byte) 0x08, (byte) 0x9d, + (byte) 0xc9, (byte) 0xf5, (byte) 0xf7, (byte) 0x81, (byte) 0x90, (byte) 0xf1, + (byte) 0xcc, (byte) 0x3f, (byte) 0x91, (byte) 0xda, (byte) 0xcb, (byte) 0x67, + (byte) 0x6a, (byte) 0xe8, (byte) 0x4a, (byte) 0xa0, (byte) 0xc3, (byte) 0x8a, + (byte) 0x53, (byte) 0xd9, (byte) 0xf0, (byte) 0x17, (byte) 0xbe, (byte) 0x90, + (byte) 0xbb, (byte) 0x95, (byte) 0x29, (byte) 0x01, (byte) 0xce, (byte) 0x32, + (byte) 0xce, (byte) 0xf8, (byte) 0x02, (byte) 0xfe, (byte) 0xe8, (byte) 0x19, + (byte) 0x91, (byte) 0x29, (byte) 0x46, (byte) 0xf7, (byte) 0x67, (byte) 0xd1, + (byte) 0xcb, (byte) 0xa7, (byte) 0x20, (byte) 0x8b, (byte) 0x85, (byte) 0x8a, + (byte) 0x0c, (byte) 0x07, (byte) 0xf8, (byte) 0xfe, (byte) 0xf4, (byte) 0x5d, + (byte) 0x08, (byte) 0xf4, (byte) 0x63, (byte) 0x4a, (byte) 0x69, (byte) 0x66, + (byte) 0x28, (byte) 0xcb, (byte) 0x0d, (byte) 0x1c, (byte) 0x7f, (byte) 0x7f, + (byte) 0x7e, (byte) 0x83, (byte) 0x49, (byte) 0x66, (byte) 0x6c, (byte) 0x83, + (byte) 0x2d, (byte) 0xa0, (byte) 0x51, (byte) 0xf6, (byte) 0x14, (byte) 0x68, + (byte) 0x47, (byte) 0x31, (byte) 0x72, (byte) 0x4d, (byte) 0xe9, (byte) 0x1e, + (byte) 0x12, (byte) 0x1b, (byte) 0xd0, (byte) 0xe6, (byte) 0x21, (byte) 0xd8, + (byte) 0x84, (byte) 0x5f, (byte) 0xe3, (byte) 0xef, (byte) 0x02, (byte) 0x03, + (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80, + (byte) 0x24, (byte) 0x95, (byte) 0xb8, (byte) 0xe1, (byte) 0xf4, (byte) 0x7b, + (byte) 0xbc, (byte) 0x0c, (byte) 0x6d, (byte) 0x4d, (byte) 0x01, (byte) 0xe2, + (byte) 0x42, (byte) 0xe2, (byte) 0x9a, (byte) 0xe4, (byte) 0xab, (byte) 0xe2, + (byte) 0x9a, (byte) 0x8c, (byte) 0xd5, (byte) 0x93, (byte) 0xe8, (byte) 0x43, + (byte) 0x77, (byte) 0x85, (byte) 0xfd, (byte) 0xf3, (byte) 0xd8, (byte) 0xd6, + (byte) 0xe9, (byte) 0x02, (byte) 0xf3, (byte) 0xbf, (byte) 0x82, (byte) 0x65, + (byte) 0xc3, (byte) 0x7c, (byte) 0x96, (byte) 0x09, (byte) 0x04, (byte) 0x16, + (byte) 0x1d, (byte) 0x03, (byte) 0x3d, (byte) 0x82, (byte) 0xb8, (byte) 0xdc, + (byte) 0xbb, (byte) 0xd6, (byte) 0xbf, (byte) 0x2a, (byte) 0x52, (byte) 0x83, + (byte) 0x76, (byte) 0x5b, (byte) 0xae, (byte) 0x59, (byte) 0xf6, (byte) 0xee, + (byte) 0x84, (byte) 0x44, (byte) 0x4a, (byte) 0xa7, (byte) 0x25, (byte) 0x50, + (byte) 0x89, (byte) 0x63, (byte) 0x43, (byte) 0x0b, (byte) 0xc8, (byte) 0xd5, + (byte) 0x17, (byte) 0x9d, (byte) 0x8b, (byte) 0x62, (byte) 0xd5, (byte) 0xf1, + (byte) 0xde, (byte) 0x45, (byte) 0xe6, (byte) 0x35, (byte) 0x10, (byte) 0xba, + (byte) 0x58, (byte) 0x18, (byte) 0x44, (byte) 0xc1, (byte) 0x6d, (byte) 0xb6, + (byte) 0x1d, (byte) 0x2f, (byte) 0x53, (byte) 0xb6, (byte) 0x5a, (byte) 0xf1, + (byte) 0x66, (byte) 0xbc, (byte) 0x0e, (byte) 0x63, (byte) 0xa7, (byte) 0x0f, + (byte) 0x81, (byte) 0x4b, (byte) 0x07, (byte) 0x31, (byte) 0xa5, (byte) 0x70, + (byte) 0xec, (byte) 0x30, (byte) 0x57, (byte) 0xc4, (byte) 0x14, (byte) 0xb2, + (byte) 0x8b, (byte) 0x6f, (byte) 0x26, (byte) 0x7e, (byte) 0x55, (byte) 0x60, + (byte) 0x63, (byte) 0x7d, (byte) 0x90, (byte) 0xd7, (byte) 0x5f, (byte) 0xef, + (byte) 0x7d, (byte) 0xc1, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xfe, + (byte) 0x92, (byte) 0xa9, (byte) 0xf1, (byte) 0x29, (byte) 0x1e, (byte) 0xd4, + (byte) 0x72, (byte) 0xd3, (byte) 0x3f, (byte) 0x9d, (byte) 0xd6, (byte) 0x3d, + (byte) 0xe9, (byte) 0xcf, (byte) 0x3e, (byte) 0x06, (byte) 0xdc, (byte) 0x65, + (byte) 0x8f, (byte) 0xc0, (byte) 0x81, (byte) 0xc2, (byte) 0x66, (byte) 0xc1, + (byte) 0x5c, (byte) 0x2c, (byte) 0xfa, (byte) 0x08, (byte) 0x65, (byte) 0xb6, + (byte) 0x47, (byte) 0xc5, (byte) 0x14, (byte) 0x8d, (byte) 0x69, (byte) 0xe9, + (byte) 0xaf, (byte) 0x42, (byte) 0x02, (byte) 0x53, (byte) 0x04, (byte) 0x63, + (byte) 0x47, (byte) 0xaf, (byte) 0xcc, (byte) 0xae, (byte) 0x08, (byte) 0x31, + (byte) 0xba, (byte) 0xea, (byte) 0x85, (byte) 0xda, (byte) 0xd6, (byte) 0xb2, + (byte) 0xe7, (byte) 0x4c, (byte) 0xda, (byte) 0xad, (byte) 0x52, (byte) 0x76, + (byte) 0x48, (byte) 0x16, (byte) 0xeb, (byte) 0x02, (byte) 0x41, (byte) 0x00, + (byte) 0xef, (byte) 0xc4, (byte) 0x7d, (byte) 0x69, (byte) 0x7b, (byte) 0xcb, + (byte) 0xcb, (byte) 0xf7, (byte) 0x00, (byte) 0x2d, (byte) 0x05, (byte) 0x3c, + (byte) 0xe4, (byte) 0xfd, (byte) 0x5c, (byte) 0xea, (byte) 0xcf, (byte) 0x40, + (byte) 0x84, (byte) 0x10, (byte) 0xf1, (byte) 0xc0, (byte) 0xaf, (byte) 0xc7, + (byte) 0xc8, (byte) 0x51, (byte) 0xac, (byte) 0x18, (byte) 0x25, (byte) 0x63, + (byte) 0x75, (byte) 0xc7, (byte) 0x0e, (byte) 0xa9, (byte) 0xed, (byte) 0x9c, + (byte) 0x78, (byte) 0x08, (byte) 0x28, (byte) 0x1d, (byte) 0x9e, (byte) 0xfa, + (byte) 0x17, (byte) 0x0f, (byte) 0x7a, (byte) 0x6a, (byte) 0x78, (byte) 0x63, + (byte) 0x6e, (byte) 0xb3, (byte) 0x6b, (byte) 0xd6, (byte) 0x43, (byte) 0x4b, + (byte) 0x58, (byte) 0xb8, (byte) 0x77, (byte) 0x10, (byte) 0x07, (byte) 0x70, + (byte) 0xa6, (byte) 0xa9, (byte) 0xae, (byte) 0x0d, (byte) 0x02, (byte) 0x41, + (byte) 0x00, (byte) 0x92, (byte) 0x4c, (byte) 0x79, (byte) 0x0b, (byte) 0x95, + (byte) 0xc5, (byte) 0x18, (byte) 0xf4, (byte) 0x90, (byte) 0x40, (byte) 0x8c, + (byte) 0x15, (byte) 0x96, (byte) 0x69, (byte) 0x2a, (byte) 0xe7, (byte) 0x8b, + (byte) 0x8b, (byte) 0xd7, (byte) 0x76, (byte) 0x00, (byte) 0x7c, (byte) 0xd1, + (byte) 0xda, (byte) 0xb9, (byte) 0x9e, (byte) 0x9e, (byte) 0x5e, (byte) 0x66, + (byte) 0xbb, (byte) 0x05, (byte) 0x41, (byte) 0x43, (byte) 0x9a, (byte) 0x67, + (byte) 0x16, (byte) 0x89, (byte) 0xec, (byte) 0x65, (byte) 0x33, (byte) 0xee, + (byte) 0xbf, (byte) 0xa3, (byte) 0xca, (byte) 0x8b, (byte) 0xd6, (byte) 0x45, + (byte) 0xe1, (byte) 0x81, (byte) 0xaa, (byte) 0xd8, (byte) 0xa2, (byte) 0x6a, + (byte) 0x3c, (byte) 0x5e, (byte) 0x7e, (byte) 0x1c, (byte) 0xa5, (byte) 0xc3, + (byte) 0x5b, (byte) 0x93, (byte) 0x8c, (byte) 0x24, (byte) 0x57, (byte) 0x02, + (byte) 0x40, (byte) 0x0a, (byte) 0x6d, (byte) 0x3f, (byte) 0x0e, (byte) 0xf1, + (byte) 0x45, (byte) 0x41, (byte) 0x8f, (byte) 0x72, (byte) 0x40, (byte) 0x82, + (byte) 0xf3, (byte) 0xcc, (byte) 0xf9, (byte) 0x7f, (byte) 0xaa, (byte) 0xee, + (byte) 0x6c, (byte) 0x5d, (byte) 0xd1, (byte) 0xe6, (byte) 0xd1, (byte) 0x7c, + (byte) 0x53, (byte) 0x71, (byte) 0xd0, (byte) 0xab, (byte) 0x6d, (byte) 0x39, + (byte) 0x63, (byte) 0x03, (byte) 0xe2, (byte) 0x2e, (byte) 0x2f, (byte) 0x11, + (byte) 0x98, (byte) 0x36, (byte) 0x58, (byte) 0x14, (byte) 0x76, (byte) 0x85, + (byte) 0x4d, (byte) 0x56, (byte) 0xe7, (byte) 0x63, (byte) 0x69, (byte) 0x71, + (byte) 0xe6, (byte) 0xd1, (byte) 0x0f, (byte) 0x98, (byte) 0x66, (byte) 0xee, + (byte) 0xf2, (byte) 0x3d, (byte) 0xdf, (byte) 0x77, (byte) 0xbe, (byte) 0x08, + (byte) 0xb4, (byte) 0xcb, (byte) 0x6a, (byte) 0xa1, (byte) 0x99, (byte) 0x02, + (byte) 0x40, (byte) 0x52, (byte) 0x01, (byte) 0xde, (byte) 0x62, (byte) 0xc2, + (byte) 0x25, (byte) 0xbf, (byte) 0x5d, (byte) 0x77, (byte) 0xe4, (byte) 0x6b, + (byte) 0xb6, (byte) 0xd7, (byte) 0x8f, (byte) 0x89, (byte) 0x2c, (byte) 0xe6, + (byte) 0x8d, (byte) 0xe5, (byte) 0xad, (byte) 0x39, (byte) 0x17, (byte) 0x54, + (byte) 0x2b, (byte) 0x35, (byte) 0x53, (byte) 0xd1, (byte) 0xa1, (byte) 0xef, + (byte) 0x48, (byte) 0xbc, (byte) 0x95, (byte) 0x48, (byte) 0xcf, (byte) 0x62, + (byte) 0xf4, (byte) 0x33, (byte) 0xcf, (byte) 0x37, (byte) 0x78, (byte) 0xeb, + (byte) 0x17, (byte) 0xb4, (byte) 0x0b, (byte) 0x83, (byte) 0x4f, (byte) 0xb6, + (byte) 0xab, (byte) 0x7d, (byte) 0x67, (byte) 0x3e, (byte) 0x4e, (byte) 0x44, + (byte) 0x4a, (byte) 0x55, (byte) 0x2e, (byte) 0x34, (byte) 0x12, (byte) 0x0b, + (byte) 0x59, (byte) 0xb3, (byte) 0xb1, (byte) 0x1e, (byte) 0x3d}; + + + /** + * Generated from above and converted with: + * + * openssl x509 -outform d -in usercert.pem | xxd -i | sed 's/0x/(byte) 0x/g' + */ + private static final byte[] USER_CERT = + {(byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0xd8, (byte) 0x30, (byte) 0x82, + (byte) 0x01, (byte) 0xc0, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, + (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x0d, + (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, + (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x0b, (byte) 0x05, + (byte) 0x00, (byte) 0x30, (byte) 0x33, (byte) 0x31, (byte) 0x0b, (byte) 0x30, + (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, + (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13, + (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, + (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74, + (byte) 0x65, (byte) 0x31, (byte) 0x0f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x06, + (byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, + (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x32, + (byte) 0x30, (byte) 0x33, (byte) 0x32, (byte) 0x35, (byte) 0x30, (byte) 0x37, + (byte) 0x32, (byte) 0x30, (byte) 0x31, (byte) 0x32, (byte) 0x5a, (byte) 0x17, + (byte) 0x0d, (byte) 0x33, (byte) 0x32, (byte) 0x30, (byte) 0x33, (byte) 0x32, + (byte) 0x32, (byte) 0x30, (byte) 0x37, (byte) 0x32, (byte) 0x30, (byte) 0x31, + (byte) 0x32, (byte) 0x5a, (byte) 0x30, (byte) 0x33, (byte) 0x31, (byte) 0x0b, + (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31, + (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f, + (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61, + (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x0f, (byte) 0x30, (byte) 0x0d, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, + (byte) 0x06, (byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, + (byte) 0x65, (byte) 0x30, (byte) 0x81, (byte) 0x9f, (byte) 0x30, (byte) 0x0d, + (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, + (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, + (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x8d, (byte) 0x00, (byte) 0x30, + (byte) 0x81, (byte) 0x89, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, + (byte) 0xee, (byte) 0x6e, (byte) 0x51, (byte) 0xa8, (byte) 0xc4, (byte) 0x44, + (byte) 0xd9, (byte) 0xb7, (byte) 0x53, (byte) 0xf1, (byte) 0xb9, (byte) 0x1b, + (byte) 0x9d, (byte) 0x8d, (byte) 0x7c, (byte) 0x9f, (byte) 0x06, (byte) 0xe7, + (byte) 0xed, (byte) 0xa8, (byte) 0x05, (byte) 0xb8, (byte) 0xaa, (byte) 0x0a, + (byte) 0x2d, (byte) 0x74, (byte) 0x05, (byte) 0x8b, (byte) 0xad, (byte) 0xfe, + (byte) 0xd3, (byte) 0x3e, (byte) 0x08, (byte) 0x9d, (byte) 0xc9, (byte) 0xf5, + (byte) 0xf7, (byte) 0x81, (byte) 0x90, (byte) 0xf1, (byte) 0xcc, (byte) 0x3f, + (byte) 0x91, (byte) 0xda, (byte) 0xcb, (byte) 0x67, (byte) 0x6a, (byte) 0xe8, + (byte) 0x4a, (byte) 0xa0, (byte) 0xc3, (byte) 0x8a, (byte) 0x53, (byte) 0xd9, + (byte) 0xf0, (byte) 0x17, (byte) 0xbe, (byte) 0x90, (byte) 0xbb, (byte) 0x95, + (byte) 0x29, (byte) 0x01, (byte) 0xce, (byte) 0x32, (byte) 0xce, (byte) 0xf8, + (byte) 0x02, (byte) 0xfe, (byte) 0xe8, (byte) 0x19, (byte) 0x91, (byte) 0x29, + (byte) 0x46, (byte) 0xf7, (byte) 0x67, (byte) 0xd1, (byte) 0xcb, (byte) 0xa7, + (byte) 0x20, (byte) 0x8b, (byte) 0x85, (byte) 0x8a, (byte) 0x0c, (byte) 0x07, + (byte) 0xf8, (byte) 0xfe, (byte) 0xf4, (byte) 0x5d, (byte) 0x08, (byte) 0xf4, + (byte) 0x63, (byte) 0x4a, (byte) 0x69, (byte) 0x66, (byte) 0x28, (byte) 0xcb, + (byte) 0x0d, (byte) 0x1c, (byte) 0x7f, (byte) 0x7f, (byte) 0x7e, (byte) 0x83, + (byte) 0x49, (byte) 0x66, (byte) 0x6c, (byte) 0x83, (byte) 0x2d, (byte) 0xa0, + (byte) 0x51, (byte) 0xf6, (byte) 0x14, (byte) 0x68, (byte) 0x47, (byte) 0x31, + (byte) 0x72, (byte) 0x4d, (byte) 0xe9, (byte) 0x1e, (byte) 0x12, (byte) 0x1b, + (byte) 0xd0, (byte) 0xe6, (byte) 0x21, (byte) 0xd8, (byte) 0x84, (byte) 0x5f, + (byte) 0xe3, (byte) 0xef, (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, + (byte) 0x01, (byte) 0xa3, (byte) 0x7b, (byte) 0x30, (byte) 0x79, (byte) 0x30, + (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, + (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00, (byte) 0x30, (byte) 0x2c, + (byte) 0x06, (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01, + (byte) 0x86, (byte) 0xf8, (byte) 0x42, (byte) 0x01, (byte) 0x0d, (byte) 0x04, + (byte) 0x1f, (byte) 0x16, (byte) 0x1d, (byte) 0x4f, (byte) 0x70, (byte) 0x65, + (byte) 0x6e, (byte) 0x53, (byte) 0x53, (byte) 0x4c, (byte) 0x20, (byte) 0x47, + (byte) 0x65, (byte) 0x6e, (byte) 0x65, (byte) 0x72, (byte) 0x61, (byte) 0x74, + (byte) 0x65, (byte) 0x64, (byte) 0x20, (byte) 0x43, (byte) 0x65, (byte) 0x72, + (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63, (byte) 0x61, + (byte) 0x74, (byte) 0x65, (byte) 0x30, (byte) 0x1d, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, (byte) 0x04, + (byte) 0x14, (byte) 0xee, (byte) 0xec, (byte) 0x08, (byte) 0xcc, (byte) 0xdd, + (byte) 0xa3, (byte) 0x29, (byte) 0x6e, (byte) 0x2b, (byte) 0x78, (byte) 0x23, + (byte) 0xb3, (byte) 0xf0, (byte) 0xb8, (byte) 0x9d, (byte) 0x53, (byte) 0x41, + (byte) 0x2e, (byte) 0x3c, (byte) 0x61, (byte) 0x30, (byte) 0x1f, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, (byte) 0x18, + (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x86, (byte) 0xdb, + (byte) 0xa5, (byte) 0x5e, (byte) 0x0e, (byte) 0x03, (byte) 0xbc, (byte) 0xe4, + (byte) 0xc1, (byte) 0xc8, (byte) 0xf3, (byte) 0xed, (byte) 0x24, (byte) 0x48, + (byte) 0xb1, (byte) 0x37, (byte) 0x3a, (byte) 0x52, (byte) 0x10, (byte) 0x57, + (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, + (byte) 0x0b, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, (byte) 0x01, + (byte) 0x01, (byte) 0x00, (byte) 0x15, (byte) 0x5a, (byte) 0x5c, (byte) 0x08, + (byte) 0xe4, (byte) 0x0e, (byte) 0x28, (byte) 0x4c, (byte) 0xa9, (byte) 0x0e, + (byte) 0x35, (byte) 0xbe, (byte) 0xe3, (byte) 0xd5, (byte) 0xd1, (byte) 0xb4, + (byte) 0x47, (byte) 0x87, (byte) 0x63, (byte) 0xd2, (byte) 0x5e, (byte) 0x7e, + (byte) 0xf6, (byte) 0xd8, (byte) 0xce, (byte) 0xdf, (byte) 0x10, (byte) 0x15, + (byte) 0x61, (byte) 0xc4, (byte) 0x9a, (byte) 0xf1, (byte) 0xba, (byte) 0x33, + (byte) 0xf2, (byte) 0xc2, (byte) 0x01, (byte) 0x95, (byte) 0xa7, (byte) 0x74, + (byte) 0x97, (byte) 0xc1, (byte) 0x43, (byte) 0x68, (byte) 0x92, (byte) 0xbe, + (byte) 0x9a, (byte) 0x6f, (byte) 0x38, (byte) 0xcb, (byte) 0xa0, (byte) 0xcf, + (byte) 0x1e, (byte) 0x5b, (byte) 0x03, (byte) 0xde, (byte) 0x45, (byte) 0x6d, + (byte) 0xea, (byte) 0xf0, (byte) 0x46, (byte) 0x4d, (byte) 0xb6, (byte) 0x4b, + (byte) 0x88, (byte) 0xc7, (byte) 0xb8, (byte) 0xe3, (byte) 0x9f, (byte) 0x58, + (byte) 0x8b, (byte) 0x2d, (byte) 0xbf, (byte) 0x4b, (byte) 0x3f, (byte) 0x54, + (byte) 0x2d, (byte) 0xa8, (byte) 0x27, (byte) 0x72, (byte) 0x5e, (byte) 0x36, + (byte) 0x67, (byte) 0x5c, (byte) 0x6e, (byte) 0x9a, (byte) 0x67, (byte) 0x73, + (byte) 0x44, (byte) 0xaf, (byte) 0x46, (byte) 0x7f, (byte) 0xd6, (byte) 0x2b, + (byte) 0x9d, (byte) 0x28, (byte) 0xb1, (byte) 0xc4, (byte) 0xc4, (byte) 0x72, + (byte) 0x3d, (byte) 0x6d, (byte) 0x7d, (byte) 0x28, (byte) 0x40, (byte) 0x62, + (byte) 0x40, (byte) 0x21, (byte) 0x52, (byte) 0xb5, (byte) 0x0b, (byte) 0xf3, + (byte) 0xcc, (byte) 0x36, (byte) 0x03, (byte) 0x10, (byte) 0x19, (byte) 0xe3, + (byte) 0xc2, (byte) 0xfe, (byte) 0xe9, (byte) 0x08, (byte) 0x0d, (byte) 0xd4, + (byte) 0x8b, (byte) 0x12, (byte) 0xd6, (byte) 0x3d, (byte) 0xc5, (byte) 0xb8, + (byte) 0x8c, (byte) 0xbd, (byte) 0xa5, (byte) 0xcd, (byte) 0xb3, (byte) 0xe4, + (byte) 0xd1, (byte) 0xd8, (byte) 0x4c, (byte) 0x32, (byte) 0x44, (byte) 0x3f, + (byte) 0x63, (byte) 0x32, (byte) 0x09, (byte) 0xdb, (byte) 0x8b, (byte) 0x7b, + (byte) 0x30, (byte) 0x58, (byte) 0xc7, (byte) 0xcf, (byte) 0xc3, (byte) 0x44, + (byte) 0xd9, (byte) 0xff, (byte) 0x63, (byte) 0x91, (byte) 0x74, (byte) 0xd8, + (byte) 0x62, (byte) 0x2b, (byte) 0x52, (byte) 0xc8, (byte) 0x82, (byte) 0x9f, + (byte) 0xeb, (byte) 0x22, (byte) 0x5c, (byte) 0xa2, (byte) 0x26, (byte) 0xfe, + (byte) 0x04, (byte) 0x31, (byte) 0x53, (byte) 0x09, (byte) 0xa7, (byte) 0x23, + (byte) 0xe3, (byte) 0x0f, (byte) 0xf8, (byte) 0xe9, (byte) 0x99, (byte) 0xad, + (byte) 0x4b, (byte) 0x23, (byte) 0x07, (byte) 0xfb, (byte) 0xfa, (byte) 0xc3, + (byte) 0x55, (byte) 0x59, (byte) 0xdb, (byte) 0x6b, (byte) 0x71, (byte) 0xdf, + (byte) 0x25, (byte) 0x0f, (byte) 0xaa, (byte) 0xa2, (byte) 0xfa, (byte) 0x28, + (byte) 0x49, (byte) 0x65, (byte) 0x7e, (byte) 0x0b, (byte) 0x74, (byte) 0x30, + (byte) 0xd9, (byte) 0x9a, (byte) 0xfe, (byte) 0x2c, (byte) 0x8c, (byte) 0x67, + (byte) 0x50, (byte) 0x0c, (byte) 0x6d, (byte) 0x4c, (byte) 0xba, (byte) 0x34, + (byte) 0x3b, (byte) 0x0d, (byte) 0x16, (byte) 0x45, (byte) 0x63, (byte) 0x73, + (byte) 0xc2, (byte) 0x9f, (byte) 0xb4, (byte) 0xdd, (byte) 0x6f, (byte) 0xde, + (byte) 0x9d, (byte) 0x71, (byte) 0xbf, (byte) 0x8d, (byte) 0x1b, (byte) 0x79, + (byte) 0xa0, (byte) 0x0a, (byte) 0x66, (byte) 0x7e, (byte) 0x56, (byte) 0x83, + (byte) 0x8f, (byte) 0x3f, (byte) 0x7d, (byte) 0x93, (byte) 0xf6, (byte) 0xc9, + (byte) 0x42, (byte) 0xfc, (byte) 0xc5, (byte) 0xf2, (byte) 0x49, (byte) 0xec}; + + @After + public void tearDown() { + try { + mDevicePolicyManager.removeKeyPair(mComponentName, mContext.getString(R.string.alias)); + mDevicePolicyManager.clearDeviceOwnerApp(mContext.getPackageName()); + } catch (Exception e) { + // ignore all exceptions as the test is already complete + } + } + + @Test + public void testOverlayButtonPresence() { + try { + /* Install key pair required to launch KeyChainActivity dialog */ + mContext = getInstrumentation().getContext(); + Resources resources = mContext.getResources(); + KeyFactory kf = KeyFactory.getInstance(mContext.getString(R.string.keyType)); + PrivateKey privKey = kf.generatePrivate(new PKCS8EncodedKeySpec(PRIVATE_KEY)); + CertificateFactory cf = + CertificateFactory.getInstance(mContext.getString(R.string.certType)); + Certificate cert = cf.generateCertificate(new ByteArrayInputStream(USER_CERT)); + mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class); + mComponentName = new ComponentName(PocDeviceAdminReceiver.class.getPackage().getName(), + PocDeviceAdminReceiver.class.getName()); + assumeTrue(mDevicePolicyManager.installKeyPair(mComponentName, privKey, cert, + mContext.getString(R.string.alias))); + + /* Start the overlay service */ + Intent intent = new Intent(mContext, PocService.class); + assumeTrue(mContext.getString(R.string.canNotDrawOverlaysMsg), + Settings.canDrawOverlays(mContext)); + CompletableFuture<PocStatus> callbackReturn = new CompletableFuture<>(); + RemoteCallback cb = new RemoteCallback((Bundle result) -> { + PocStatus pocStatus = + new PocStatus(result.getInt(mContext.getString(R.string.statusKey)), + result.getString(mContext.getString(R.string.messageKey))); + callbackReturn.complete(pocStatus); + }); + intent.putExtra(mContext.getString(R.string.callbackKey), cb); + mContext.startService(intent); + PocStatus result = callbackReturn.get(resources.getInteger(R.integer.timeoutMs), + TimeUnit.MILLISECONDS); + assumeTrue(result.getErrorMessage(), + result.getStatusCode() != resources.getInteger(R.integer.assumptionFailure)); + + /* Wait for the overlay window */ + Pattern overlayTextPattern = Pattern.compile( + mContext.getString(R.string.overlayButtonText), Pattern.CASE_INSENSITIVE); + UiDevice device = UiDevice.getInstance(getInstrumentation()); + assumeTrue(mContext.getString(R.string.overlayUiScreenError), + device.wait(Until.hasObject(By.text(overlayTextPattern)), + mContext.getResources().getInteger(R.integer.timeoutMs))); + + /* Start PocActivity which starts the vulnerable activity */ + intent = new Intent(mContext, PocActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + CompletableFuture<PocStatus> pocActivityReturn = new CompletableFuture<>(); + RemoteCallback pocActivityCb = new RemoteCallback((Bundle pocActivityResult) -> { + PocStatus pocStatus = new PocStatus( + pocActivityResult.getInt(mContext.getString(R.string.statusKey)), + pocActivityResult.getString(mContext.getString(R.string.messageKey))); + pocActivityReturn.complete(pocStatus); + }); + intent.putExtra(mContext.getString(R.string.callbackKey), pocActivityCb); + mContext.startActivity(intent); + result = pocActivityReturn.get(resources.getInteger(R.integer.timeoutMs), + TimeUnit.MILLISECONDS); + assumeTrue(result.getErrorMessage(), + result.getStatusCode() != resources.getInteger(R.integer.assumptionFailure)); + + /* Get the vulnerable activity name by using an alternative intent */ + Intent vulIntent = new Intent(mContext.getString(R.string.actionKeychainActivity)); + ResolveInfo ri = mContext.getPackageManager().resolveActivity(vulIntent, + PackageManager.MATCH_DEFAULT_ONLY); + String vulnerableActivityName = ri.activityInfo.name; + + /* Wait until the object of launcher activity is gone */ + boolean overlayDisallowed = device.wait(Until.gone(By.pkg(mContext.getPackageName())), + mContext.getResources().getInteger(R.integer.timeoutMs)); + + /* Check if the currently running activity is the vulnerable activity */ + String activityDump = ""; + activityDump = device.executeShellCommand( + mContext.getString(R.string.dumpsysActivity, vulnerableActivityName)); + Pattern activityPattern = Pattern.compile(mContext.getString(R.string.mResumedTrue), + Pattern.CASE_INSENSITIVE); + assumeTrue( + mContext.getString(R.string.vulActivityNotRunningError, vulnerableActivityName), + activityPattern.matcher(activityDump).find()); + + /* Failing the test as fix is not present */ + assertTrue(mContext.getString(R.string.errorMessage, vulnerableActivityName), + overlayDisallowed); + } catch (Exception e) { + assumeNoException(e); + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocActivity.java new file mode 100644 index 00000000000..ac8ea15c6e0 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocActivity.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package android.security.cts.CVE_2021_0963; + +import android.app.Activity; +import android.os.Bundle; +import android.os.RemoteCallback; +import android.security.KeyChain; +import android.security.KeyChainAliasCallback; + +import androidx.annotation.Nullable; + +public class PocActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + try { + super.onCreate(savedInstanceState); + KeyChainAliasCallback callback = new KeyChainAliasCallback() { + @Override + public void alias(@Nullable String alias) {} + }; + KeyChain.choosePrivateKeyAlias(this, callback, null, null, null, -1, null); + sendTestResult(getResources().getInteger(R.integer.noException), ""); + } catch (Exception e) { + sendTestResult(getResources().getInteger(R.integer.assumptionFailure), e.getMessage()); + } + } + + void sendTestResult(int status, String message) { + try { + RemoteCallback cb = + (RemoteCallback) getIntent().getExtras().get(getString(R.string.callbackKey)); + Bundle res = new Bundle(); + res.putString(getString(R.string.messageKey), message); + res.putInt(getString(R.string.statusKey), status); + cb.sendResult(res); + } catch (Exception e) { + // ignore all exceptions + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocDeviceAdminReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocDeviceAdminReceiver.java new file mode 100644 index 00000000000..5592323071b --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocDeviceAdminReceiver.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package android.security.cts.CVE_2021_0963; + +import android.app.admin.DeviceAdminReceiver; + +public class PocDeviceAdminReceiver extends DeviceAdminReceiver { +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocService.java new file mode 100644 index 00000000000..b83e8247d54 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocService.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +package android.security.cts.CVE_2021_0963; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteCallback; +import android.view.Gravity; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; +import android.widget.Button; + +public class PocService extends Service { + Button mButton; + WindowManager mWindowManager; + LayoutParams mLayoutParams; + Intent mIntent; + + private static int getScreenWidth() { + return Resources.getSystem().getDisplayMetrics().widthPixels; + } + + private static int getScreenHeight() { + return Resources.getSystem().getDisplayMetrics().heightPixels; + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + try { + mIntent = intent; + mWindowManager = getSystemService(WindowManager.class); + mLayoutParams = new LayoutParams(); + mLayoutParams.type = LayoutParams.TYPE_APPLICATION_OVERLAY; + mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL | + 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; + Context context = getApplicationContext(); + mButton = new Button(context); + mButton.setText(context.getString(R.string.overlayButtonText)); + mWindowManager.addView(mButton, mLayoutParams); + sendTestResult(getResources().getInteger(R.integer.noException), ""); + } catch (Exception e) { + sendTestResult(getResources().getInteger(R.integer.assumptionFailure), e.getMessage()); + } + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onDestroy() { + try { + mWindowManager.removeView(mButton); + } catch (Exception e) { + sendTestResult(getResources().getInteger(R.integer.assumptionFailure), e.getMessage()); + } + super.onDestroy(); + } + + void sendTestResult(int status, String message) { + try { + RemoteCallback cb = + (RemoteCallback) mIntent.getExtras().get(getString(R.string.callbackKey)); + Bundle res = new Bundle(); + res.putString(getString(R.string.messageKey), message); + res.putInt(getString(R.string.statusKey), status); + cb.sendResult(res); + } catch (Exception e) { + // ignore exception here + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocStatus.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocStatus.java new file mode 100644 index 00000000000..de67f0ff104 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocStatus.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package android.security.cts.CVE_2021_0963; + +public class PocStatus { + int statusCode; + String errorMessage; + + public PocStatus(int status, String message) { + statusCode = status; + errorMessage = message; + } + + public int getStatusCode() { + return statusCode; + } + + public String getErrorMessage() { + return errorMessage; + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/Android.bp new file mode 100644 index 00000000000..cf3b7e26fb0 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/Android.bp @@ -0,0 +1,38 @@ +/* + * 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. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2022-20112", + defaults: [ + "cts_support_defaults" + ], + srcs: [ + "src/**/*.java" + ], + test_suites: [ + "sts", + ], + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + ], + platform_apis: true, +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/AndroidManifest.xml new file mode 100644 index 00000000000..052a711b31e --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/AndroidManifest.xml @@ -0,0 +1,22 @@ +<!-- + 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.security.cts.CVE_2022_20112"> + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.CVE_2022_20112" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/res/values/strings.xml new file mode 100644 index 00000000000..af458479c47 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/res/values/strings.xml @@ -0,0 +1,24 @@ +<?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="defaultSettingsPkg">com.android.settings</string> + <string name="getAvailabilityStatusMethodName">getAvailabilityStatus</string> + <string name="privateDnsPreferenceControllerClassName">.network.PrivateDnsPreferenceController + </string> + <string name="testFailMsg">Device is vulnerable to b/206987762!! Private DNS can be modified in + guest mode</string> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/src/android/security/cts/CVE_2022_20112/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/src/android/security/cts/CVE_2022_20112/DeviceTest.java new file mode 100644 index 00000000000..96cb205134f --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20112/src/android/security/cts/CVE_2022_20112/DeviceTest.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package android.security.cts.CVE_2022_20112; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static org.junit.Assert.assertFalse; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; + +import android.app.UiAutomation; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.UserManager; +import android.provider.Settings; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + + @Test + public void testprivateDnsPreferenceController() { + UiAutomation uiAutomation = null; + try { + Context context = getInstrumentation().getTargetContext(); + + // Retrieve settings package name dynamically + Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS); + ComponentName settingsComponent = + settingsIntent.resolveActivity(context.getPackageManager()); + String settingsPkgName = settingsComponent != null ? settingsComponent.getPackageName() + : context.getString(R.string.defaultSettingsPkg); + + // Get vulnerable method 'getAvailabilityStatus' using reflection + Context settingsContext = context.createPackageContext(settingsPkgName, + Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); + ClassLoader settingsClassLoader = settingsContext.getClassLoader(); + Class<?> privateDnsPreferenceControllerClass = + settingsClassLoader.loadClass(settingsPkgName + + context.getString(R.string.privateDnsPreferenceControllerClassName)); + Constructor<?> privateDnsPreferenceControllerCstr = + privateDnsPreferenceControllerClass.getConstructor(Context.class); + Object privateDnsPreferenceControllerObject = + privateDnsPreferenceControllerCstr.newInstance(settingsContext); + Method getAvailabilityStatusMethod = privateDnsPreferenceControllerClass + .getDeclaredMethod(context.getString(R.string.getAvailabilityStatusMethodName)); + getAvailabilityStatusMethod.setAccessible(true); + + // Check if current user is guest user + uiAutomation = getInstrumentation().getUiAutomation(); + uiAutomation.adoptShellPermissionIdentity(android.Manifest.permission.CREATE_USERS); + final UserManager userManager = context.getSystemService(UserManager.class); + assumeTrue(userManager.isGuestUser()); + + // Invoke vulnerable method 'getAvailabilityStatus' + int status = + (int) getAvailabilityStatusMethod.invoke(privateDnsPreferenceControllerObject); + assertFalse(context.getString(R.string.testFailMsg), status == 0 /* AVAILABLE */); + } catch (Exception e) { + assumeNoException(e); + } finally { + try { + uiAutomation.dropShellPermissionIdentity(); + } catch (Exception ignored) { + // Ignore exception here + } + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/Android.bp new file mode 100644 index 00000000000..d9f8554c32d --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/Android.bp @@ -0,0 +1,38 @@ +/* + * 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. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2022-20360", + defaults: [ + "cts_support_defaults" + ], + srcs: [ + "src/**/*.java" + ], + test_suites: [ + "sts", + ], + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + ], + platform_apis: true, +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/AndroidManifest.xml new file mode 100644 index 00000000000..9e2361a9750 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/AndroidManifest.xml @@ -0,0 +1,23 @@ +<!-- + 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.security.cts.CVE_2022_20360"> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.CVE_2022_20360" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/res/values/strings.xml new file mode 100644 index 00000000000..9476f7af344 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/res/values/strings.xml @@ -0,0 +1,27 @@ +<?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="defaultSettingsPkg">com.android.settings</string> + <string name="disableSecureNfcFailed">Disabling secure NFC failed</string> + <string name="key">key</string> + <string name="msgDeviceLocked">Device is in sleep or locked mode</string> + <string name="msgTestFail"> Device is vulnerable to b/228314987!! Secure nfc can be disabled in + guest user via SettingsSlice</string> + <string name="secureNfcPreferenceControllerClassName">.nfc.SecureNfcPreferenceController + </string> + <string name="setCheckedMethod">setChecked</string> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/src/android/security/cts/CVE_2022_20360/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/src/android/security/cts/CVE_2022_20360/DeviceTest.java new file mode 100644 index 00000000000..9e73804e1b7 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/src/android/security/cts/CVE_2022_20360/DeviceTest.java @@ -0,0 +1,119 @@ +/* + * 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. + */ + +package android.security.cts.CVE_2022_20360; + +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; + +import android.app.KeyguardManager; +import android.app.UiAutomation; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.nfc.NfcAdapter; +import android.nfc.NfcManager; +import android.os.PowerManager; +import android.os.UserManager; +import android.provider.Settings; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + + @Test + public void testSecureNfcPreferenceController() { + boolean secureNfcEnabled = false; + NfcAdapter nfcAdapter = null; + UiAutomation uiAutomation = null; + try { + Context context = getApplicationContext(); + NfcManager nfcManager = context.getSystemService(NfcManager.class); + nfcAdapter = nfcManager.getDefaultAdapter(); + uiAutomation = getInstrumentation().getUiAutomation(); + + // Secure NFC APIs require device to be unlocked hence check if device is unlocked + PowerManager powerManager = context.getSystemService(PowerManager.class); + KeyguardManager keyguardManager = context.getSystemService(KeyguardManager.class); + assumeTrue(context.getString(R.string.msgDeviceLocked), + powerManager.isInteractive() && !keyguardManager.isKeyguardLocked()); + + + // Save secure NFC state(enabled/disabled) and disable secure NFC for test + secureNfcEnabled = nfcAdapter.isSecureNfcEnabled(); + if (secureNfcEnabled) { + nfcAdapter.enableSecureNfc(false); + } + assumeFalse(context.getString(R.string.disableSecureNfcFailed), + nfcAdapter.isSecureNfcEnabled()); + + // Retrieve settings package name dynamically + Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS); + ComponentName settingsComponent = + settingsIntent.resolveActivity(context.getPackageManager()); + String settingsPkgName = settingsComponent != null ? settingsComponent.getPackageName() + : context.getString(R.string.defaultSettingsPkg); + + // Get vulnerable method 'setChecked' using reflection + Context settingsContext = context.createPackageContext(settingsPkgName, + Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); + ClassLoader settingsClassLoader = settingsContext.getClassLoader(); + Class<?> targetClass = settingsClassLoader.loadClass(settingsPkgName + + context.getString(R.string.secureNfcPreferenceControllerClassName)); + Constructor<?> targetClassCstr = + targetClass.getConstructor(Context.class, String.class); + Object targetClassobject = + targetClassCstr.newInstance(context, context.getString(R.string.key)); + Method setCheckedMethod = targetClass + .getDeclaredMethod(context.getString(R.string.setCheckedMethod), boolean.class); + setCheckedMethod.setAccessible(true); + + // Check if current user is guest user + uiAutomation.adoptShellPermissionIdentity(android.Manifest.permission.CREATE_USERS); + UserManager userManager = context.getSystemService(UserManager.class); + assumeTrue(userManager.isGuestUser()); + + // Invoke vulnerable method 'setChecked' + boolean retVal = (boolean) setCheckedMethod.invoke(targetClassobject, true); + assertFalse(context.getString(R.string.msgTestFail), retVal); + } catch (Exception e) { + assumeNoException(e); + } finally { + try { + // Disable secure NFC if it was disabled before the test + if (!secureNfcEnabled) { + nfcAdapter.enableSecureNfc(false); + } + } catch (Exception ignored) { + // Ignore any exception here + } finally { + uiAutomation.dropShellPermissionIdentity(); + } + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/Android.bp new file mode 100644 index 00000000000..1ba587fb4aa --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/Android.bp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2022-20415", + defaults: ["cts_support_defaults"], + srcs: [ + "src/**/*.java", + ], + test_suites: [ + "sts", + ], + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + ], + sdk_version: "current", +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/AndroidManifest.xml new file mode 100644 index 00000000000..476cf0b26e6 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/AndroidManifest.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2023 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="android.security.cts.CVE_2022_20415"> + <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" /> + <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> + <application> + <activity + android:name=".PocActivity" + android:exported="true"> + </activity> + </application> + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.CVE_2022_20415" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/res/values/integers.xml new file mode 100644 index 00000000000..f2cba3d0623 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/res/values/integers.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2023 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="height">50</integer> + <integer name="idSummaryNotification">0</integer> + <integer name="idTestNotification">1</integer> + <integer name="requestCodeIntent">0</integer> + <integer name="width">50</integer> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/res/values/strings.xml new file mode 100644 index 00000000000..195d69661fe --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/res/values/strings.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2023 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="idNotificationChannel">testId</string> + <string name="msgFailure">Device is vulnerable to b/231322873 !!</string> + <string name="nameBroadcastActionString">CVE_2022_20415_action</string> + <string name="nameNotificationChannel">b/231322873 notification</string> + <string name="tagNotify">NOTIFY_TAG</string> + <string name="textSummaryNotification">Summary Content</string> + <string name="titlePocNotification">PoC</string> + <string name="titleSummaryNotification">Summary Title</string> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/src/android/security/cts/CVE_2022_20415/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/src/android/security/cts/CVE_2022_20415/DeviceTest.java new file mode 100644 index 00000000000..687235100c6 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/src/android/security/cts/CVE_2022_20415/DeviceTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2023 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.security.cts.CVE_2022_20415; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assume.assumeNoException; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.drawable.Icon; + +import androidx.test.runner.AndroidJUnit4; + +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + private Context mContext; + private NotificationManager mNotificationManager; + private Resources mResources; + + Icon createNotificationIcon() { + Bitmap testBitmap = Bitmap.createBitmap(mResources.getInteger(R.integer.width), + mResources.getInteger(R.integer.height), Bitmap.Config.ARGB_8888); + final Canvas canvas = new Canvas(testBitmap); + canvas.drawColor(Color.BLUE); + return Icon.createWithBitmap(testBitmap); + } + + public void tryNotificationStart() throws Exception { + Icon icon = createNotificationIcon(); + PendingIntent pendingIntent = PendingIntent.getActivity(mContext, + mResources.getInteger(R.integer.requestCodeIntent), + new Intent(mContext, PocActivity.class), PendingIntent.FLAG_IMMUTABLE); + NotificationChannel notificationChannel = + new NotificationChannel(mContext.getString(R.string.idNotificationChannel), + mContext.getString(R.string.nameNotificationChannel), + NotificationManager.IMPORTANCE_MAX); + notificationChannel.setDescription(mContext.getString(R.string.nameNotificationChannel)); + mNotificationManager.createNotificationChannel(notificationChannel); + Notification summaryNotification = new Notification.Builder(mContext, + mContext.getString(R.string.idNotificationChannel)) + .setContentTitle(mContext.getString(R.string.titleSummaryNotification)) + .setContentText(mContext.getString(R.string.textSummaryNotification)) + .setSmallIcon(icon).setGroup(mContext.getPackageName()) + .setGroupSummary(true /* make summaryNotification a group summary */) + .build(); + Notification pocNotification = new Notification.Builder(mContext, + mContext.getString(R.string.idNotificationChannel)).setSmallIcon(icon) + .setContentTitle(mContext.getString(R.string.titlePocNotification)) + .setGroupAlertBehavior(Notification.GROUP_ALERT_SUMMARY) + .setGroup(mContext.getPackageName()) + .setFullScreenIntent(pendingIntent, true /* high priority */).build(); + + mNotificationManager.notify(mContext.getString(R.string.tagNotify), + mResources.getInteger(R.integer.idTestNotification), pocNotification); + mNotificationManager.notify(mResources.getInteger(R.integer.idSummaryNotification), + summaryNotification); + } + + @Test + public void testFullScreenIntent() { + try { + mContext = getInstrumentation().getTargetContext(); + mNotificationManager = mContext.getSystemService(NotificationManager.class); + mResources = mContext.getResources(); + Semaphore mBroadcastReceived = new Semaphore(0); + int timeoutMs = 20000; + + // Register a broadcast receiver to receive broadcast from PocActivity indicating + // presence of vulnerability + BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + try { + if (intent.getAction() + .equals(mContext.getString(R.string.nameBroadcastActionString))) { + mBroadcastReceived.release(); + } + } catch (Exception ignored) { + // ignore any exceptions + } + } + }; + IntentFilter filter = + new IntentFilter(mContext.getString(R.string.nameBroadcastActionString)); + mContext.registerReceiver(broadcastReceiver, filter); + + tryNotificationStart(); + assertFalse(mContext.getString(R.string.msgFailure), + mBroadcastReceived.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)); + } catch (Exception e) { + assumeNoException(e); + } finally { + try { + mNotificationManager.cancel(mResources.getInteger(R.integer.idSummaryNotification)); + mNotificationManager.cancel(mContext.getString(R.string.tagNotify), + mResources.getInteger(R.integer.idTestNotification)); + } catch (Exception e) { + // ignore this exception + } + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/src/android/security/cts/CVE_2022_20415/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/src/android/security/cts/CVE_2022_20415/PocActivity.java new file mode 100644 index 00000000000..5afa1914562 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20415/src/android/security/cts/CVE_2022_20415/PocActivity.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023 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.security.cts.CVE_2022_20415; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +public class PocActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + try { + super.onCreate(savedInstanceState); + // PocActivity has been launched successfully, this indicates presence of vulnerability + // so broadcasting it to DeviceTest. + sendBroadcast(new Intent(getString(R.string.nameBroadcastActionString))); + } catch (Exception e) { + // ignore any exceptions + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/Android.bp index 770b5a2089e..81ce65dffbd 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/Android.bp +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/Android.bp @@ -15,12 +15,18 @@ * */ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + android_test_helper_app { - name: "CVE-2021-0642", + name: "CVE-2023-20913", defaults: [ "cts_support_defaults", ], - srcs: ["src/**/*.java"], + srcs: [ + "src/**/*.java", + ], test_suites: [ "sts", ], @@ -29,5 +35,4 @@ android_test_helper_app { "androidx.test.rules", "androidx.test.uiautomator_uiautomator", ], - sdk_version: "current", } diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/AndroidManifest.xml new file mode 100644 index 00000000000..5617874ad3d --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/AndroidManifest.xml @@ -0,0 +1,27 @@ +<?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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.security.cts.CVE_2023_20913"> + <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> + <application> + <service android:name=".PocService" /> + </application> + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.CVE_2023_20913" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/res/values/strings.xml new file mode 100644 index 00000000000..dc0aa2a5932 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/res/values/strings.xml @@ -0,0 +1,35 @@ +<?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="activityAccessibilitySettings">.settings.AccessibilitySettingsActivity</string> + <string name="activityPhoneAccountSettings">.settings.PhoneAccountSettingsActivity</string> + <string name="activityVoicemailSettings">.settings.VoicemailSettingsActivity</string> + <string name="dumpsysActivityCmd">dumpsys activity %1$s</string> + <string name="mResumedTrue">mResumed=true</string> + <string name="msgActivityNotFound">The activity with intent %1$s was not found</string> + <string name="msgAssumptionFailure">Following assumption failures occurred: </string> + <string name="msgCannotDrawOverlays">The application cannot draw overlays</string> + <string name="msgDeviceLocked">Device is in sleep or locked mode</string> + <string name="msgOverlayError">Device is vulnerable to b/246933785 hence any app with + "SYSTEM_ALERT_WINDOW permission" can overlay the following activities: </string> + <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string> + <string name="pkgDefaultTelephony">com.android.phone</string> + <string name="textOverlayButton">b_246933785 OverlayButton</string> + <string name="vulActivityNotRunningError">The %1$s is not currently running on the device + </string> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/src/android/security/cts/CVE_2023_20913/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/src/android/security/cts/CVE_2023_20913/DeviceTest.java new file mode 100644 index 00000000000..49b26be5911 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/src/android/security/cts/CVE_2023_20913/DeviceTest.java @@ -0,0 +1,161 @@ +/* + * 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. + */ + +package android.security.cts.CVE_2023_20913; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; + +import android.app.KeyguardManager; +import android.app.UiAutomation; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.PowerManager; +import android.os.UserHandle; +import android.provider.Settings; +import android.telecom.TelecomManager; + +import androidx.test.runner.AndroidJUnit4; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.Until; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + private Context mContext = null; + private List<String> mViolations; + private List<String> mVulnerabilities; + PackageManager mPackageManager = null; + + private String getTelephonyPackageName() { + UiAutomation ui = getInstrumentation().getUiAutomation(); + String name = mContext.getString(R.string.pkgDefaultTelephony); + try { + ui.adoptShellPermissionIdentity(android.Manifest.permission.INTERACT_ACROSS_USERS); + Intent intent = new Intent(TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS); + ResolveInfo info = mPackageManager.resolveActivityAsUser(intent, + PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM); + name = info.activityInfo.packageName; + } catch (Exception e) { + assumeNoException(e); + } finally { + ui.dropShellPermissionIdentity(); + } + return name; + } + + public void testActivity(String cls) throws Exception { + UiDevice device = null; + try { + mPackageManager = mContext.getPackageManager(); + device = UiDevice.getInstance(getInstrumentation()); + + // Start the overlay service + Intent serviceIntent = new Intent(mContext, PocService.class); + assumeTrue(mContext.getString(R.string.msgCannotDrawOverlays), + Settings.canDrawOverlays(mContext)); + mContext.startService(serviceIntent); + + // Wait for the overlay window + Pattern overlayTextPattern = Pattern.compile( + mContext.getString(R.string.textOverlayButton), Pattern.CASE_INSENSITIVE); + final long launchTimeoutMs = 20_000L; + if (!device.wait(Until.hasObject(By.text(overlayTextPattern)), launchTimeoutMs)) { + mViolations.add(cls + mContext.getString(R.string.overlayUiScreenError)); + return; + } + + // Start the vulnerable activity + String pkg = getTelephonyPackageName(); + Intent intent = new Intent(); + String vulActivity = pkg + cls; + intent.setClassName(pkg, vulActivity); + ResolveInfo ri = + mPackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); + if (ri == null) { + mViolations.add(cls + mContext.getString(R.string.msgActivityNotFound, intent)); + return; + } + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + mContext.startActivity(intent); + + // Wait until overlay window is gone + boolean overlayDisallowed = + device.wait(Until.gone(By.text(overlayTextPattern)), launchTimeoutMs); + + // Check if the currently running activity is the vulnerable activity + String activityDump = device.executeShellCommand( + mContext.getString(R.string.dumpsysActivityCmd, vulActivity)); + Pattern activityPattern = Pattern.compile(mContext.getString(R.string.mResumedTrue), + Pattern.CASE_INSENSITIVE); + if (!(activityPattern.matcher(activityDump).find())) { + mViolations.add( + cls + mContext.getString(R.string.vulActivityNotRunningError, vulActivity)); + return; + } + + // If overlayDisallowed is not true then add the class name to mVulnerabilities + if (!overlayDisallowed) { + mVulnerabilities.add(cls); + } + } catch (Exception e) { + mViolations.add(e.getMessage()); + } finally { + try { + // To exit current activity so that new activity starts + device.pressHome(); + } catch (Exception e) { + // Ignoring exceptions here since any exception caught here is unrelated to test + } + } + } + + @Test + public void testOverlayButtonPresence() { + try { + mContext = getInstrumentation().getTargetContext(); + KeyguardManager keyguardManager = mContext.getSystemService(KeyguardManager.class); + PowerManager powerManager = mContext.getSystemService(PowerManager.class); + assumeTrue(mContext.getString(R.string.msgDeviceLocked), + powerManager.isInteractive() && !keyguardManager.isKeyguardLocked()); + mViolations = new ArrayList<String>(); + mVulnerabilities = new ArrayList<String>(); + testActivity(mContext.getString(R.string.activityAccessibilitySettings)); + testActivity(mContext.getString(R.string.activityPhoneAccountSettings)); + testActivity(mContext.getString(R.string.activityVoicemailSettings)); + if (mVulnerabilities.isEmpty()) { + assumeTrue(mContext.getString(R.string.msgAssumptionFailure) + mViolations, + mViolations.isEmpty()); + } else { + fail(mContext.getString(R.string.msgOverlayError) + mVulnerabilities); + } + } catch (Exception e) { + assumeNoException(e); + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/src/android/security/cts/CVE_2023_20913/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/src/android/security/cts/CVE_2023_20913/PocService.java new file mode 100644 index 00000000000..6ac55d98cff --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20913/src/android/security/cts/CVE_2023_20913/PocService.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package android.security.cts.CVE_2023_20913; + +import android.app.Service; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.os.IBinder; +import android.util.DisplayMetrics; +import android.view.Gravity; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; +import android.widget.Button; + +public class PocService extends Service { + private Button mButton; + private WindowManager mWindowManager; + + @Override + public void onCreate() { + 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; + DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics(); + layoutParams.width = displayMetrics.widthPixels; + layoutParams.height = displayMetrics.heightPixels; + layoutParams.x = displayMetrics.widthPixels / 2; + layoutParams.y = displayMetrics.heightPixels / 2; + + // Show the floating window + mButton = new Button(this); + mButton.setText(getString(R.string.textOverlayButton)); + mWindowManager.addView(mButton, layoutParams); + } catch (Exception ignored) { + // In case of occurrence of an exception overlay won't appear on display which results + // in assumption failure in device test. Hence ignoring this exception here. + } + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public void onDestroy() { + try { + mWindowManager.removeView(mButton); + super.onDestroy(); + } catch (Exception ignored) { + // Ignoring unintended exceptions + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/Android.bp new file mode 100644 index 00000000000..af4ad21c319 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/Android.bp @@ -0,0 +1,35 @@ +/* + * 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. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2023-20918-attacker", + defaults: [ + "cts_support_defaults", + ], + srcs: [ + "src/**/*.java", + ], + test_suites: [ + "sts", + ], + // platform_apis set to true here to access hidden method setPendingIntentLaunchFlags + platform_apis: true, +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/AndroidManifest.xml new file mode 100644 index 00000000000..bcc3ad1373a --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/AndroidManifest.xml @@ -0,0 +1,23 @@ +<!-- + 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.security.cts.CVE_2023_20918_attacker"> + <application> + <activity android:name=".ExploitActivity" + android:exported="true" /> + </application> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/res/values/strings.xml new file mode 100644 index 00000000000..9523eca2ace --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/res/values/strings.xml @@ -0,0 +1,27 @@ +<?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> + <string name="bcastActionTestAssumeFail">CVE_2023_20918_assume_fail_action</string> + <string name="bcastActionTestFail">CVE_2023_20918_test_fail_action</string> + <string name="bcastActionTestPass">CVE_2023_20918_test_pass_action</string> + <string name="contentUri">content://authority_CVE_2023_20918_test/file_path/poc.txt</string> + <string name="expActivityExploit">Got an exception in ExploitActivity with message: %1$s + </string> + <string name="keyMsgAssumeFail">msg</string> + <string name="keyPendingIntent">pi</string> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/src/android/security/cts/CVE_2023_20918_attacker/ExploitActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/src/android/security/cts/CVE_2023_20918_attacker/ExploitActivity.java new file mode 100644 index 00000000000..1693cac7b68 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/attacker-app/src/android/security/cts/CVE_2023_20918_attacker/ExploitActivity.java @@ -0,0 +1,83 @@ +/* + * 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. + */ + +package android.security.cts.CVE_2023_20918_attacker; + +import android.app.Activity; +import android.app.ActivityOptions; +import android.app.PendingIntent; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; + +public class ExploitActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + try { + super.onCreate(savedInstanceState); + Intent intent = getIntent(); + final String keyPendingIntent = getString(R.string.keyPendingIntent); + + // If intent contains 'keyPendingIntent', then this activity is launched again using + // the custom intent that the extra 'keyPendingIntent' holds. + if (intent.hasExtra(keyPendingIntent)) { + PendingIntent activity = intent.getParcelableExtra(keyPendingIntent); + ActivityOptions options = ActivityOptions.makeBasic(); + options.setPendingIntentLaunchFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + activity.send(this, 0, null, null, null, "", options.toBundle()); + } else if (intent.getData() != null) { + // Control goes in this block when the activity is launched again. Attempting to + // open uri data received from the intent. + Uri data = intent.getData(); + getContentResolver().openOutputStream(data); + + // If control reaches here, then it means that openOutputStream() did not raise an + // exception, this indicates that FLAG_GRANT_WRITE_URI_PERMISSION has been granted + // so sending a broadcast to DeviceTest with the test_fail status. + sendBroadcastToTestApp(getString(R.string.bcastActionTestFail)); + } + } catch (Exception e) { + if (e instanceof SecurityException + && e.getMessage().contains(getString(R.string.keyPendingIntent))) { + // ignoring this exception since it occurs with fix + sendBroadcastToTestApp(getString(R.string.bcastActionTestPass)); + return; + } + + // Sending a broadcast to DeviceTest to indicate assumption failure status, + // since an exception was raised unrelated to the vulnerability + sendBroadcastToTestApp(getString(R.string.bcastActionTestAssumeFail), + getString(R.string.expActivityExploit, e.getMessage())); + } + } + + public void sendBroadcastToTestApp(String action) { + sendBroadcastToTestApp(action, null); + } + + public void sendBroadcastToTestApp(String action, String assumeFailMsg) { + try { + Intent intent = new Intent(action); + if (assumeFailMsg != null) { + intent.putExtra(getString(R.string.keyMsgAssumeFail), assumeFailMsg); + } + sendBroadcast(intent); + } catch (Exception ignored) { + // ignore the exceptions + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/Android.bp new file mode 100644 index 00000000000..a32ae6c9dee --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/Android.bp @@ -0,0 +1,40 @@ +/* + * 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. + * + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "CVE-2023-20918-test", + defaults: [ + "cts_support_defaults", + ], + srcs: [ + "src/**/*.java", + ], + test_suites: [ + "sts", + ], + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + // including this to use androidx.core.content.FileProvider + "androidx.legacy_legacy-support-v4", + ], + sdk_version: "current", +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/AndroidManifest.xml new file mode 100644 index 00000000000..b95b6d7a52c --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/AndroidManifest.xml @@ -0,0 +1,29 @@ +<!-- + 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.security.cts.CVE_2023_20918_test"> + <application> + <provider android:name="androidx.core.content.FileProvider" + android:authorities="authority_CVE_2023_20918_test" + android:grantUriPermissions="true"> + <meta-data android:name="android.support.FILE_PROVIDER_PATHS" + android:resource="@xml/file_paths" /> + </provider> + </application> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.security.cts.CVE_2023_20918_test" /> +</manifest> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/values/strings.xml new file mode 100644 index 00000000000..40b8d361140 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/values/strings.xml @@ -0,0 +1,31 @@ +<?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> + <string name="activityExploit">android.security.cts.CVE_2023_20918_attacker.ExploitActivity + </string> + <string name="bcastActionTestAssumeFail">CVE_2023_20918_assume_fail_action</string> + <string name="bcastActionTestFail">CVE_2023_20918_test_fail_action</string> + <string name="bcastActionTestPass">CVE_2023_20918_test_pass_action</string> + <string name="contentUri">content://authority_CVE_2023_20918_test/file_path/poc.txt</string> + <string name="fileContents">This is a read only file\n</string> + <string name="keyMsgAssumeFail">msg</string> + <string name="keyPendingIntent">pi</string> + <string name="msgAssumeFailDefault">Got an exception in DeviceTest.java</string> + <string name="msgFail">Device is vulnerable to b/243794108 !!</string> + <string name="pkgAttacker">android.security.cts.CVE_2023_20918_attacker</string> +</resources> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/xml/file_paths.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/xml/file_paths.xml new file mode 100644 index 00000000000..dd4259b19db --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/res/xml/file_paths.xml @@ -0,0 +1,20 @@ +<?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. + --> + +<paths> + <files-path name="file_path" path="./" /> +</paths> diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/src/android/security/cts/CVE_2023_20918_test/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/src/android/security/cts/CVE_2023_20918_test/DeviceTest.java new file mode 100644 index 00000000000..e677938d6ba --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20918/test-app/src/android/security/cts/CVE_2023_20918_test/DeviceTest.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +package android.security.cts.CVE_2023_20918_test; + +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assume.assumeNoException; + +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.Uri; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +public class DeviceTest { + private static final long TIMEOUT_MS = 10_000L; + private String mAssumeFailMsg; + + @Test + public void testCVE_2023_20918() { + try { + Context context = getApplicationContext(); + mAssumeFailMsg = context.getString(R.string.msgAssumeFailDefault); + final CompletableFuture<Boolean> exploitActivityReturn = new CompletableFuture<>(); + final String bcastActionFail = context.getString(R.string.bcastActionTestFail); + final String bcastActionPass = context.getString(R.string.bcastActionTestPass); + final String bcastActionAssumeFail = + context.getString(R.string.bcastActionTestAssumeFail); + + // Register a broadcast receiver to receive broadcast from ExploitActivity indicating + // presence of vulnerability + BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + try { + if (intent.getAction().equals(bcastActionFail)) { + exploitActivityReturn.complete(true); + } else if (intent.getAction().equals(bcastActionPass)) { + exploitActivityReturn.complete(false); + } else if (intent.getAction().equals(bcastActionAssumeFail)) { + // mAssumeFailMsg set here is used in assumeNoException() triggered + // when exploitActivityReturn.get() raises a timeout exception + mAssumeFailMsg = intent + .getStringExtra(context.getString(R.string.keyMsgAssumeFail)); + } + } catch (Exception ignored) { + // ignore the exceptions + } + } + }; + IntentFilter filter = new IntentFilter(); + filter.addAction(bcastActionFail); + filter.addAction(bcastActionPass); + filter.addAction(bcastActionAssumeFail); + context.registerReceiver(broadcastReceiver, filter); + + // Write some data to the Uri content://authority/file_path/poc.txt + final String uriString = context.getString(R.string.contentUri); + try (OutputStream outputStream = + context.getContentResolver().openOutputStream(Uri.parse(uriString));) { + outputStream.write( + context.getString(R.string.fileContents).getBytes(StandardCharsets.UTF_8)); + } + + // Creating an intent to launch ExploitActivity + Intent intent = new Intent(); + final String attackerPkg = context.getString(R.string.pkgAttacker); + final String exploitActivity = context.getString(R.string.activityExploit); + intent.setClassName(attackerPkg, exploitActivity); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + // Creating the inner intent for PendingIntent + Intent innerIntent = new Intent(Intent.ACTION_MAIN, Uri.parse(uriString)); + innerIntent.setClassName(attackerPkg, exploitActivity); + innerIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + innerIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + // Launch the ExploitActivity passing PendingIntent as data + intent.putExtra(context.getString(R.string.keyPendingIntent), PendingIntent + .getActivity(context, 0, innerIntent, PendingIntent.FLAG_IMMUTABLE)); + context.startActivity(intent); + + // On vulnerable device, the PendingIntent launchIntentFlags will be added even though + // it is immutable, so the test should fail if the flags are found to take effect. + assertFalse(context.getString(R.string.msgFail), + exploitActivityReturn.get(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } catch (Exception e) { + assumeNoException(mAssumeFailMsg, e); + } + } +} diff --git a/tests/app/AndroidManifest.xml b/tests/app/AndroidManifest.xml index 4ff6cb27df2..97e6fd649f3 100644 --- a/tests/app/AndroidManifest.xml +++ b/tests/app/AndroidManifest.xml @@ -27,6 +27,10 @@ <application android:usesCleartextTraffic="true"> <uses-library android:name="android.test.runner" /> <uses-library android:name="org.apache.http.legacy" android:required="false" /> + + <service android:name=".InstrumentationHelperService" + android:exported="true" + android:process=":helper" /> </application> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" @@ -55,4 +59,11 @@ android:targetProcesses="com.android.cts.launcherapps.simpleapp:other,com.android.cts.launcherapps.simpleapp"> </instrumentation> + <instrumentation android:name=".ChainedInstrumentationFirst" + android:targetPackage="com.android.test.cantsavestate1" > + </instrumentation> + + <instrumentation android:name=".ChainedInstrumentationSecond" + android:targetPackage="com.android.test.cantsavestate2" > + </instrumentation> </manifest> diff --git a/tests/app/src/android/app/cts/BaseChainedInstrumentation.java b/tests/app/src/android/app/cts/BaseChainedInstrumentation.java new file mode 100644 index 00000000000..d265263dc4d --- /dev/null +++ b/tests/app/src/android/app/cts/BaseChainedInstrumentation.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package android.app.cts; + +import android.app.Activity; +import android.app.Application; +import android.app.Instrumentation; +import android.content.ComponentName; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; + +/** + * Base class supporting "chained" instrumentation: start another instrumentation while + * running the current instrumentation. + */ +public class BaseChainedInstrumentation extends Instrumentation { + static final String EXTRA_MESSENGER = "messenger"; + + final ComponentName mNestedInstrComp; + + /** Constructor */ + public BaseChainedInstrumentation(ComponentName nestedInstrComp) { + mNestedInstrComp = nestedInstrComp; + } + + @Override + public void onCreate(Bundle arguments) { + super.onCreate(arguments); + final String proc = getProcessName(); + final String appProc = Application.getProcessName(); + if (!proc.equals(appProc)) { + throw new RuntimeException(String.format( + "getProcessName()s mismatch. Instr=%s App=%s", proc, appProc)); + } + final Bundle result = new Bundle(); + result.putBoolean(proc, true); + if (mNestedInstrComp != null) { + // We're in the main process. + // Because the Context#startInstrumentation doesn't support result watcher, + // we'd have to craft a private way to relay the result back. + final Handler handler = new Handler(Looper.myLooper(), msg -> { + final Bundle nestedResult = (Bundle) msg.obj; + result.putAll(nestedResult); + finish(Activity.RESULT_OK, result); + return true; + }); + final Messenger messenger = new Messenger(handler); + final Bundle extras = new Bundle(); + extras.putParcelable(EXTRA_MESSENGER, messenger); + getContext().startInstrumentation(mNestedInstrComp, null, extras); + scheduleTimeoutCleanup(); + } else { + final Messenger messenger = arguments.getParcelable(EXTRA_MESSENGER); + final Message msg = Message.obtain(); + try { + msg.obj = result; + messenger.send(msg); + } catch (RemoteException e) { + } finally { + msg.recycle(); + } + finish(Activity.RESULT_OK, result); + } + } + + private void scheduleTimeoutCleanup() { + new Handler(Looper.myLooper()).postDelayed(() -> { + Bundle result = new Bundle(); + result.putString("FAILURE", + "Timed out waiting for sub-instrumentation to complete"); + finish(Activity.RESULT_CANCELED, result); + }, 20 * 1000); + } +} diff --git a/tests/app/src/android/app/cts/ChainedInstrumentationFirst.java b/tests/app/src/android/app/cts/ChainedInstrumentationFirst.java new file mode 100644 index 00000000000..0fd22b06cbf --- /dev/null +++ b/tests/app/src/android/app/cts/ChainedInstrumentationFirst.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package android.app.cts; + +import android.content.ComponentName; + +/** + * Chained instrumentation test class. + */ +public final class ChainedInstrumentationFirst extends BaseChainedInstrumentation { + static final String PACKAGE_NAME = "android.app.cts"; + /** Constructor */ + public ChainedInstrumentationFirst() { + super(new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".ChainedInstrumentationSecond")); + } +} diff --git a/tests/app/src/android/app/cts/ChainedInstrumentationSecond.java b/tests/app/src/android/app/cts/ChainedInstrumentationSecond.java new file mode 100644 index 00000000000..ebed475c0c0 --- /dev/null +++ b/tests/app/src/android/app/cts/ChainedInstrumentationSecond.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package android.app.cts; + +/** + * Chained instrumentation test class. + */ +public final class ChainedInstrumentationSecond extends BaseChainedInstrumentation { + /** Constructor */ + public ChainedInstrumentationSecond() { + super(null); + } +} diff --git a/tests/app/src/android/app/cts/InstrumentationHelperService.java b/tests/app/src/android/app/cts/InstrumentationHelperService.java new file mode 100644 index 00000000000..0c4f48d626a --- /dev/null +++ b/tests/app/src/android/app/cts/InstrumentationHelperService.java @@ -0,0 +1,83 @@ +/* + * 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. + */ + +package android.app.cts; + +import android.app.Service; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.IBinder; +import android.os.ResultReceiver; + +import java.util.concurrent.CountDownLatch; + +/** + * The helper class to start an instrumentation from a different process. + */ +public class InstrumentationHelperService extends Service { + private static final String ACTION_START_INSTRUMENTATION = + "android.app.cts.ACTION_START_INSTRUMENTATION"; + private static final String EXTRA_INSTRUMENTATIION_NAME = "instrumentation_name"; + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + final String action = intent.getAction(); + if (ACTION_START_INSTRUMENTATION.equals(action)) { + final String instrumentationName = intent.getStringExtra(EXTRA_INSTRUMENTATIION_NAME); + final ResultReceiver r = intent.getParcelableExtra(Intent.EXTRA_RESULT_RECEIVER); + + boolean result = false; + try { + startInstrumentation( + ComponentName.unflattenFromString(instrumentationName), null, null); + result = true; + } catch (SecurityException e) { + } + r.send(result ? 1 : 0, null); + } + return START_NOT_STICKY; + } + + /** + * Start the given instrumentation from this service and return result. + */ + static boolean startInstrumentation(Context context, String instrumentationName) + throws InterruptedException { + final Intent intent = new Intent(ACTION_START_INSTRUMENTATION); + final boolean[] resultHolder = new boolean[1]; + final CountDownLatch latch = new CountDownLatch(1); + final ResultReceiver r = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + resultHolder[0] = resultCode == 1; + latch.countDown(); + } + }; + intent.putExtra(EXTRA_INSTRUMENTATIION_NAME, instrumentationName); + intent.putExtra(Intent.EXTRA_RESULT_RECEIVER, r); + intent.setClassName("android.app.cts", "android.app.cts.InstrumentationHelperService"); + context.startService(intent); + latch.await(); + return resultHolder[0]; + } +} diff --git a/tests/app/src/android/app/cts/InstrumentationTest.java b/tests/app/src/android/app/cts/InstrumentationTest.java index 396c20d5a72..0a2c071deb3 100644 --- a/tests/app/src/android/app/cts/InstrumentationTest.java +++ b/tests/app/src/android/app/cts/InstrumentationTest.java @@ -16,6 +16,15 @@ package android.app.cts; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; + import android.app.Activity; import android.app.Application; import android.app.Instrumentation; @@ -32,10 +41,11 @@ import android.content.res.Configuration; import android.graphics.Point; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Debug; import android.os.SystemClock; -import android.test.InstrumentationTestCase; +import android.os.SystemProperties; import android.test.UiThreadTest; import android.view.InputQueue; import android.view.KeyCharacterMap; @@ -47,16 +57,24 @@ import android.view.View; import android.view.ViewGroup.LayoutParams; import android.view.Window; -import java.util.List; - import android.app.stubs.R; import com.android.compatibility.common.util.PollingCheck; import com.android.compatibility.common.util.SystemUtil; import androidx.test.filters.FlakyTest; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; -public class InstrumentationTest extends InstrumentationTestCase { +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.List; + +@RunWith(AndroidJUnit4.class) +public class InstrumentationTest { private static final int WAIT_TIME = 1000; @@ -70,10 +88,9 @@ public class InstrumentationTest extends InstrumentationTestCase { private Context mContext; private MockActivity mMockActivity; - @Override - protected void setUp() throws Exception { - super.setUp(); - mInstrumentation = getInstrumentation(); + @Before + public void setUp() throws Exception { + mInstrumentation = InstrumentationRegistry.getInstrumentation(); mContext = mInstrumentation.getTargetContext(); mIntent = new Intent(mContext, InstrumentationTestActivity.class); mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); @@ -81,47 +98,87 @@ public class InstrumentationTest extends InstrumentationTestCase { PollingCheck.waitFor(mActivity::hasWindowFocus); } - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { mInstrumentation = null; mIntent = null; if (mActivity != null) { mActivity.finish(); mActivity = null; } - super.tearDown(); } + @Test public void testDefaultProcessInstrumentation() throws Exception { String cmd = "am instrument -w android.app.cts/.DefaultProcessInstrumentation"; - String result = SystemUtil.runShellCommand(getInstrumentation(), cmd); + String result = SystemUtil.runShellCommand(mInstrumentation, cmd); assertEquals("INSTRUMENTATION_RESULT: " + SIMPLE_PACKAGE_NAME + "=true" + "\nINSTRUMENTATION_CODE: -1\n", result); } + @Test public void testAltProcessInstrumentation() throws Exception { String cmd = "am instrument -w android.app.cts/.AltProcessInstrumentation"; - String result = SystemUtil.runShellCommand(getInstrumentation(), cmd); + String result = SystemUtil.runShellCommand(mInstrumentation, cmd); assertEquals("INSTRUMENTATION_RESULT: " + SIMPLE_PACKAGE_NAME + ":other=true" + "\nINSTRUMENTATION_CODE: -1\n", result); } @FlakyTest(bugId = 133760851) + @Test public void testWildcardProcessInstrumentation() throws Exception { String cmd = "am instrument -w android.app.cts/.WildcardProcessInstrumentation"; - String result = SystemUtil.runShellCommand(getInstrumentation(), cmd); + String result = SystemUtil.runShellCommand(mInstrumentation, cmd); assertEquals("INSTRUMENTATION_RESULT: " + SIMPLE_PACKAGE_NAME + "=true" + "\nINSTRUMENTATION_RESULT: " + SIMPLE_PACKAGE_NAME + ":receiver=true" + "\nINSTRUMENTATION_CODE: -1\n", result); } + @Test public void testMultiProcessInstrumentation() throws Exception { String cmd = "am instrument -w android.app.cts/.MultiProcessInstrumentation"; - String result = SystemUtil.runShellCommand(getInstrumentation(), cmd); + String result = SystemUtil.runShellCommand(mInstrumentation, cmd); assertEquals("INSTRUMENTATION_RESULT: " + SIMPLE_PACKAGE_NAME + "=true" + "\nINSTRUMENTATION_RESULT: " + SIMPLE_PACKAGE_NAME + ":other=true" + "\nINSTRUMENTATION_CODE: -1\n", result); } + @Test + public void testEnforceStartFromShell() throws Exception { + assumeFalse(SystemProperties.getBoolean("ro.debuggable", false)); + // Start the instrumentation from shell, it should succeed. + final String defaultInstrumentationName = "android.app.cts/.DefaultProcessInstrumentation"; + String cmd = "am instrument -w " + defaultInstrumentationName; + String result = SystemUtil.runShellCommand(mInstrumentation, cmd); + assertEquals("INSTRUMENTATION_RESULT: " + SIMPLE_PACKAGE_NAME + "=true" + + "\nINSTRUMENTATION_CODE: -1\n", result); + // Start the instrumentation by ourselves, it should succeed (chained instrumentation). + mContext.startInstrumentation( + ComponentName.unflattenFromString(defaultInstrumentationName), null, null); + // Start the instrumentation from another process, this time it should fail. + SystemUtil.runShellCommand(mInstrumentation, + "cmd deviceidle tempwhitelist android.app.cts"); + try { + assertFalse(InstrumentationHelperService.startInstrumentation( + mContext, defaultInstrumentationName)); + } finally { + SystemUtil.runShellCommand(mInstrumentation, + "cmd deviceidle tempwhitelist -r android.app.cts"); + } + } + + @Test + public void testChainedInstrumentation() throws Exception { + final String testPkg1 = "com.android.test.cantsavestate1"; + final String testPkg2 = "com.android.test.cantsavestate2"; + String cmd = "am instrument -w android.app.cts/.ChainedInstrumentationFirst"; + String result = SystemUtil.runShellCommand(mInstrumentation, cmd); + assertEquals("INSTRUMENTATION_RESULT: " + testPkg1 + "=true" + + "\nINSTRUMENTATION_RESULT: " + testPkg2 + "=true" + + "\nINSTRUMENTATION_CODE: -1\n", result); + } + + @Test public void testMonitor() throws Exception { if (mActivity != null) mActivity.finish(); @@ -162,6 +219,7 @@ public class InstrumentationTest extends InstrumentationTestCase { mInstrumentation.removeMonitor(am); } + @Test public void testCallActivityOnCreate() throws Throwable { mActivity.setOnCreateCalled(false); runTestOnUiThread(new Runnable() { @@ -173,6 +231,7 @@ public class InstrumentationTest extends InstrumentationTestCase { assertTrue(mActivity.isOnCreateCalled()); } + @Test public void testAllocCounting() throws Exception { mInstrumentation.startAllocCounting(); @@ -208,6 +267,7 @@ public class InstrumentationTest extends InstrumentationTestCase { } @FlakyTest(bugId = 133760851) + @Test public void testSendTrackballEventSync() throws Exception { long now = SystemClock.uptimeMillis(); MotionEvent orig = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, @@ -222,6 +282,7 @@ public class InstrumentationTest extends InstrumentationTestCase { } @FlakyTest(bugId = 133760851) + @Test public void testCallApplicationOnCreate() throws Exception { InstrumentationTestStub ca = new InstrumentationTestStub(); mInstrumentation.callApplicationOnCreate(ca); @@ -229,12 +290,14 @@ public class InstrumentationTest extends InstrumentationTestCase { } @FlakyTest(bugId = 133760851) + @Test public void testContext() throws Exception { Context c1 = mInstrumentation.getContext(); Context c2 = mInstrumentation.getTargetContext(); assertNotSame(c1.getPackageName(), c2.getPackageName()); } + @Test public void testInvokeMenuActionSync() throws Exception { final int resId = R.id.goto_menu_id; if (mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL)) { @@ -245,6 +308,7 @@ public class InstrumentationTest extends InstrumentationTestCase { } } + @Test public void testCallActivityOnPostCreate() throws Throwable { mActivity.setOnPostCreate(false); runTestOnUiThread(new Runnable() { @@ -256,6 +320,7 @@ public class InstrumentationTest extends InstrumentationTestCase { assertTrue(mActivity.isOnPostCreate()); } + @Test public void testCallActivityOnNewIntent() throws Throwable { mActivity.setOnNewIntentCalled(false); runTestOnUiThread(new Runnable() { @@ -269,6 +334,7 @@ public class InstrumentationTest extends InstrumentationTestCase { } @FlakyTest(bugId = 133760851) + @Test public void testCallActivityOnResume() throws Throwable { mActivity.setOnResume(false); runTestOnUiThread(new Runnable() { @@ -280,15 +346,18 @@ public class InstrumentationTest extends InstrumentationTestCase { assertTrue(mActivity.isOnResume()); } + @Test public void testMisc() throws Exception { } + @Test public void testPerformanceSnapshot() throws Exception { mInstrumentation.setAutomaticPerformanceSnapshots(); mInstrumentation.startPerformanceSnapshot(); mInstrumentation.endPerformanceSnapshot(); } + @Test public void testProfiling() throws Exception { // by default, profiling was disabled. but after set the handleProfiling attribute in the // manifest file for this Instrumentation to true, the profiling was also disabled. @@ -298,6 +367,7 @@ public class InstrumentationTest extends InstrumentationTestCase { mInstrumentation.stopProfiling(); } + @Test public void testInvokeContextMenuAction() throws Exception { mActivity.runOnUiThread(new Runnable() { public void run() { @@ -314,6 +384,7 @@ public class InstrumentationTest extends InstrumentationTestCase { assertEquals(flag, mMockActivity.mWindow.mFlags); } + @Test public void testSendStringSync() { final String text = "abcd"; mInstrumentation.sendStringSync(text); @@ -335,6 +406,7 @@ public class InstrumentationTest extends InstrumentationTestCase { } @FlakyTest(bugId = 133760851) + @Test public void testCallActivityOnSaveInstanceState() throws Throwable { final Bundle bundle = new Bundle(); mActivity.setOnSaveInstanceState(false); @@ -349,6 +421,7 @@ public class InstrumentationTest extends InstrumentationTestCase { assertSame(bundle, mActivity.getBundle()); } + @Test public void testSendPointerSync() throws Exception { mInstrumentation.waitForIdleSync(); mInstrumentation.setInTouchMode(true); @@ -371,13 +444,15 @@ public class InstrumentationTest extends InstrumentationTestCase { mActivity.setOnTouchEventCalled(false); } + @Test public void testGetComponentName() throws Exception { - ComponentName com = getInstrumentation().getComponentName(); + ComponentName com = mInstrumentation.getComponentName(); assertNotNull(com.getPackageName()); assertNotNull(com.getClassName()); assertNotNull(com.getShortClassName()); } + @Test public void testNewApplication() throws Exception { final String className = "android.app.stubs.MockApplication"; ClassLoader cl = getClass().getClassLoader(); @@ -389,6 +464,7 @@ public class InstrumentationTest extends InstrumentationTestCase { assertEquals(className, app.getClass().getName()); } + @Test public void testRunOnMainSync() throws Exception { mRunOnMainSyncResult = false; mInstrumentation.runOnMainSync(new Runnable() { @@ -400,6 +476,7 @@ public class InstrumentationTest extends InstrumentationTestCase { assertTrue(mRunOnMainSyncResult); } + @Test public void testCallActivityOnPause() throws Throwable { mActivity.setOnPauseCalled(false); runTestOnUiThread(() -> { @@ -409,6 +486,7 @@ public class InstrumentationTest extends InstrumentationTestCase { assertTrue(mActivity.isOnPauseCalled()); } + @Test public void testSendKeyDownUpSync() throws Exception { mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_0); mInstrumentation.waitForIdleSync(); @@ -419,6 +497,7 @@ public class InstrumentationTest extends InstrumentationTestCase { } @FlakyTest(bugId = 133760851) + @Test @UiThreadTest public void testNewActivity() throws Exception { Intent intent = new Intent(); @@ -446,6 +525,7 @@ public class InstrumentationTest extends InstrumentationTestCase { activity.finish(); } + @Test public void testCallActivityOnStart() throws Exception { mActivity.setOnStart(false); mInstrumentation.callActivityOnStart(mActivity); @@ -453,6 +533,7 @@ public class InstrumentationTest extends InstrumentationTestCase { assertTrue(mActivity.isOnStart()); } + @Test public void testWaitForIdle() throws Exception { MockRunnable mr = new MockRunnable(); assertFalse(mr.isRunCalled()); @@ -461,6 +542,7 @@ public class InstrumentationTest extends InstrumentationTestCase { assertTrue(mr.isRunCalled()); } + @Test public void testSendCharacterSync() throws Exception { mInstrumentation.sendCharacterSync(KeyEvent.KEYCODE_0); mInstrumentation.waitForIdleSync(); @@ -469,6 +551,7 @@ public class InstrumentationTest extends InstrumentationTestCase { } @FlakyTest(bugId = 133760851) + @Test public void testCallActivityOnRestart() throws Exception { mActivity.setOnRestart(false); mInstrumentation.callActivityOnRestart(mActivity); @@ -476,6 +559,7 @@ public class InstrumentationTest extends InstrumentationTestCase { assertTrue(mActivity.isOnRestart()); } + @Test public void testCallActivityOnStop() throws Exception { mActivity.setOnStop(false); mInstrumentation.callActivityOnStop(mActivity); @@ -484,6 +568,7 @@ public class InstrumentationTest extends InstrumentationTestCase { } @FlakyTest(bugId = 133760851) + @Test public void testCallActivityOnUserLeaving() throws Exception { assertFalse(mActivity.isOnLeave()); mInstrumentation.callActivityOnUserLeaving(mActivity); @@ -491,6 +576,7 @@ public class InstrumentationTest extends InstrumentationTestCase { assertTrue(mActivity.isOnLeave()); } + @Test public void testCallActivityOnRestoreInstanceState() throws Exception { mActivity.setOnRestoreInstanceState(false); mInstrumentation.callActivityOnRestoreInstanceState(mActivity, new Bundle()); @@ -498,6 +584,7 @@ public class InstrumentationTest extends InstrumentationTestCase { assertTrue(mActivity.isOnRestoreInstanceState()); } + @Test public void testSendKeySync() throws Exception { KeyEvent key = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0); mInstrumentation.sendKeySync(key); @@ -761,4 +848,20 @@ public class InstrumentationTest extends InstrumentationTestCase { mIsOnCreateCalled = true; } } + + private void runTestOnUiThread(final Runnable r) throws Throwable { + final Throwable[] exceptions = new Throwable[1]; + mInstrumentation.runOnMainSync(new Runnable() { + public void run() { + try { + r.run(); + } catch (Throwable throwable) { + exceptions[0] = throwable; + } + } + }); + if (exceptions[0] != null) { + throw exceptions[0]; + } + } } diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml index c6d60bc12f6..ce2035827b8 100644 --- a/tests/tests/security/AndroidManifest.xml +++ b/tests/tests/security/AndroidManifest.xml @@ -179,6 +179,26 @@ android:resource="@xml/syncadapter" /> </service> + <activity android:name="android.security.cts.CVE_2021_0642.PocActivity" + android:exported="true"> + <intent-filter> + <action android:name="android.telephony.action.CONFIGURE_VOICEMAIL" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + <intent-filter> + <action android:name="CVE_2021_0642_ACTION" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + + <activity android:name="android.security.cts.CVE_2021_0642.SecondActivity" + android:exported="true"> + <intent-filter> + <action android:name="CVE_2021_0642_ACTION" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + </application> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" diff --git a/tests/tests/security/res/raw/cve_2022_33234.mkv b/tests/tests/security/res/raw/cve_2022_33234.mkv Binary files differnew file mode 100644 index 00000000000..752e3cd749b --- /dev/null +++ b/tests/tests/security/res/raw/cve_2022_33234.mkv diff --git a/tests/tests/security/res/values/strings.xml b/tests/tests/security/res/values/strings.xml new file mode 100644 index 00000000000..73dd5b93d2c --- /dev/null +++ b/tests/tests/security/res/values/strings.xml @@ -0,0 +1,28 @@ +<?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> + <!-- CVE-2021-0642 --> + <string name="cve_2021_0642_action">CVE_2021_0642_ACTION</string> + <string name="cve_2021_0642_pkgPhone">com.android.phone</string> + <string name="cve_2021_0642_failMsg">Device is vulnerable to b/185126149 !!</string> + <string name="cve_2021_0642_msgResolveErrorVoicemail">The intent with action + ACTION_CONFIGURE_VOICEMAIL should resolve to either ResolverActivity or + VoicemailSettingsActivity</string> + <string name="cve_2021_0642_msgResolveErrorPocAction">The intent with action + CVE_2021_0642_ACTION should not be resolved to test package</string> +</resources> diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0642/CVE_2021_0642.java b/tests/tests/security/src/android/security/cts/CVE_2021_0642/CVE_2021_0642.java new file mode 100644 index 00000000000..b40c06b221c --- /dev/null +++ b/tests/tests/security/src/android/security/cts/CVE_2021_0642/CVE_2021_0642.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package android.security.cts.CVE_2021_0642; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.platform.test.annotations.AsbSecurityTest; +import android.security.cts.R; +import android.telephony.TelephonyManager; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; + +import java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class CVE_2021_0642 extends StsExtraBusinessLogicTestCase { + + // b/185126149 + // Vulnerable app : TeleService.apk + // Vulnerable module : com.android.phone + // Is Play managed : No + @AsbSecurityTest(cveBugId = 185126149) + @Test + public void testCVE_2021_0642() { + try { + // This test requires the device to have Telephony feature. + Context context = getInstrumentation().getTargetContext(); + PackageManager pm = context.getPackageManager(); + assumeTrue(pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)); + + // Get ResolverActivity's name and package name + Intent customIntent = new Intent(context.getString(R.string.cve_2021_0642_action)); + ResolveInfo riCustomAction = + pm.resolveActivity(customIntent, PackageManager.MATCH_DEFAULT_ONLY); + assumeTrue(context.getString(R.string.cve_2021_0642_msgResolveErrorPocAction), + !riCustomAction.activityInfo.packageName.equals(context.getPackageName())); + final String resolverPkgName = riCustomAction.activityInfo.packageName; + final String resolverActivityName = riCustomAction.activityInfo.name; + + // Resolving intent with action "ACTION_CONFIGURE_VOICEMAIL" + Intent intent = new Intent(TelephonyManager.ACTION_CONFIGURE_VOICEMAIL); + ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); + final String resolvedPkgName = ri.activityInfo.packageName; + final String resolvedActivityName = ri.activityInfo.name; + + // Check if intent resolves to either VoicemailActivity or ResolverActivity + boolean isVoicemailActivity = + resolvedPkgName.equals(context.getString(R.string.cve_2021_0642_pkgPhone)); + boolean isResolverActivity = resolvedPkgName.equals(resolverPkgName) + && resolvedActivityName.equals(resolverActivityName); + + assumeTrue(context.getString(R.string.cve_2021_0642_msgResolveErrorVoicemail), + isVoicemailActivity || isResolverActivity); + + // If vulnerability is present, the intent with action ACTION_CONFIGURE_VOICEMAIL + // would resolve to the IntentResolver i.e. ResolverActivity, the test would fail in + // this case. + assertFalse(context.getString(R.string.cve_2021_0642_failMsg), isResolverActivity); + } catch (Exception e) { + assumeNoException(e); + } + } +} diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java b/tests/tests/security/src/android/security/cts/CVE_2021_0642/PocActivity.java index 1a335c76444..ae73b016d76 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0642/src/android/security/cts/cve_2021_0642/PocActivity.java +++ b/tests/tests/security/src/android/security/cts/CVE_2021_0642/PocActivity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.security.cts.cve_2021_0642; +package android.security.cts.CVE_2021_0642; import android.app.Activity; diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0642/SecondActivity.java b/tests/tests/security/src/android/security/cts/CVE_2021_0642/SecondActivity.java new file mode 100644 index 00000000000..4c0caeedc2c --- /dev/null +++ b/tests/tests/security/src/android/security/cts/CVE_2021_0642/SecondActivity.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package android.security.cts.CVE_2021_0642; + +import android.app.Activity; + +public class SecondActivity extends Activity { +} diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20456.java b/tests/tests/security/src/android/security/cts/CVE_2022_20456.java new file mode 100644 index 00000000000..26434336a3e --- /dev/null +++ b/tests/tests/security/src/android/security/cts/CVE_2022_20456.java @@ -0,0 +1,208 @@ +/* + * 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. + */ + +package android.security.cts; + +import static android.app.NotificationManager.INTERRUPTION_FILTER_UNKNOWN; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeNoException; + +import android.app.AutomaticZenRule; +import android.content.ComponentName; +import android.net.Uri; +import android.os.Parcel; +import android.platform.test.annotations.AsbSecurityTest; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + + +// This CTS test has been created taking reference from the tests present in +// frameworks/base/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java +@RunWith(AndroidJUnit4.class) +public class CVE_2022_20456 extends StsExtraBusinessLogicTestCase { + private static final int INPUT_STRING_LENGTH = 2000; // 2 * 'MAX_STRING_LENGTH' + private static final String CLASS_NAME = "className"; + private static final String PACKAGE_NAME = "packageName"; + private static final String URI_STRING = "condition://android"; + private static final String ZEN_RULE_NAME = "ZenRuleName"; + private ComponentName mComponentNameWithLongFields; + private ComponentName mValidComponentName; + private String mLongString; + private Uri mLongUri; + private Uri mValidUri; + private List<String> mViolations; + + private void checkFields(AutomaticZenRule rule, boolean ownerFlag, boolean configActivityFlag, + String tag) { + // Check all fields + if (INPUT_STRING_LENGTH <= rule.getName().length()) { + mViolations.add(tag + "input string length <= rule name length"); + } + if (mLongUri.toString().length() <= rule.getConditionId().toString().length()) { + mViolations.add(tag + "input uri length <= rule conditionId length"); + } + if (ownerFlag) { + if (INPUT_STRING_LENGTH <= rule.getOwner().getPackageName().length()) { + mViolations.add(tag + "input string length <= rule owner package name length"); + } + if (INPUT_STRING_LENGTH <= rule.getOwner().getClassName().length()) { + mViolations.add(tag + "input string length <= rule owner class name length"); + } + } + if (configActivityFlag) { + if (INPUT_STRING_LENGTH <= rule.getConfigurationActivity().getPackageName().length()) { + mViolations.add(tag + + "input string length <= rule configurationActivity package name length"); + } + if (INPUT_STRING_LENGTH <= rule.getConfigurationActivity().getClassName().length()) { + mViolations.add(tag + + "input string length <= rule configurationActivity class name length"); + } + } + } + + private void checkConstructor(boolean ownerFlag, boolean configActivityFlag) { + ComponentName owner = ownerFlag ? mComponentNameWithLongFields : null; + ComponentName configActivity = configActivityFlag ? mComponentNameWithLongFields : null; + AutomaticZenRule rule = new AutomaticZenRule(mLongString, owner, configActivity, mLongUri, + null, INTERRUPTION_FILTER_UNKNOWN, /* enabled */ true); + checkFields(rule, ownerFlag, configActivityFlag, "\ncheckConstructor (owner=" + ownerFlag + + ", configActivity=" + configActivityFlag + "): "); + } + + private void testIsConstructorVulnerable() { + // Check all three variants i.e. with owner, with configuration activity and with both + // owner and configuration activity. Although third case is mostly redundant, adding it to + // complete checks on all possible variants. + checkConstructor(/* ownerFlag */ true, /* configActivityFlag */ false); + checkConstructor(/* ownerFlag */ false, /* configActivityFlag */ true); + checkConstructor(/* ownerFlag */ true, /* configActivityFlag */ true); + } + + private void checkFieldSetters(boolean ownerFlag, boolean configActivityFlag) { + ComponentName owner = ownerFlag ? mValidComponentName : null; + ComponentName configActivity = configActivityFlag ? mValidComponentName : null; + AutomaticZenRule rule = new AutomaticZenRule(ZEN_RULE_NAME, owner, configActivity, + mValidUri, null, INTERRUPTION_FILTER_UNKNOWN, /* enabled */ true); + + // Check all fields that can be set via setter methods of AutomaticZenRule class + rule.setName(mLongString); + rule.setConditionId(mLongUri); + rule.setConfigurationActivity(mComponentNameWithLongFields); + checkFields(rule, /* ownerFlag */ false, /* configActivityFlag */ true, + "\ncheckFieldSetters (owner=" + ownerFlag + ", configActivity=" + configActivityFlag + + "): "); + } + + private void testIsFieldSetterVulnerable() { + checkFieldSetters(/* ownerFlag */ true, /* configActivityFlag */ false); + checkFieldSetters(/* ownerFlag */ false, /* configActivityFlag */ true); + checkFieldSetters(/* ownerFlag */ true, /* configActivityFlag */ true); + } + + private void checkParcelInput(boolean ownerFlag, boolean configActivityFlag) + throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException { + ComponentName owner = ownerFlag ? mValidComponentName : null; + ComponentName configActivity = configActivityFlag ? mValidComponentName : null; + AutomaticZenRule rule = new AutomaticZenRule(ZEN_RULE_NAME, owner, configActivity, + mValidUri, null, INTERRUPTION_FILTER_UNKNOWN, /* enabled */ true); + + // Create rules with long fields set directly via reflection so that we can confirm that a + // rule with too-long fields that comes in via a parcel has its fields truncated directly. + Class automaticZenRuleClass = Class.forName("android.app.AutomaticZenRule"); + Field fieldName = automaticZenRuleClass.getDeclaredField("name"); + fieldName.setAccessible(/* flag */ true); + fieldName.set(rule, mLongString); + Field fieldConditionId = automaticZenRuleClass.getDeclaredField("conditionId"); + fieldConditionId.setAccessible(/* flag */ true); + fieldConditionId.set(rule, mLongUri); + if (ownerFlag) { + Field fieldOwner = automaticZenRuleClass.getDeclaredField("owner"); + fieldOwner.setAccessible(/* flag */ true); + fieldOwner.set(rule, mComponentNameWithLongFields); + } + if (configActivityFlag) { + Field fieldConfigActivity = + automaticZenRuleClass.getDeclaredField("configurationActivity"); + fieldConfigActivity.setAccessible(/* flag */ true); + fieldConfigActivity.set(rule, mComponentNameWithLongFields); + } + + // Write AutomaticZenRule object to parcel + Parcel parcel = Parcel.obtain(); + rule.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + // Instantiate AutomaticZenRule object using parcel + AutomaticZenRule ruleFromParcel = new AutomaticZenRule(parcel); + + checkFields(ruleFromParcel, ownerFlag, configActivityFlag, "\ncheckParcelInput (owner=" + + ownerFlag + ", configActivity=" + configActivityFlag + "): "); + } + + private void testIsInputFromParcelVulnerable() + throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException { + checkParcelInput(/* ownerFlag */ true, /* configActivityFlag */ false); + checkParcelInput(/* ownerFlag */ false, /* configActivityFlag */ true); + checkParcelInput(/* ownerFlag */ true, /* configActivityFlag */ true); + } + + // b/242703460, b/242703505, b/242703780, b/242704043, b/243794204 + // Vulnerable library : framework.jar + // Vulnerable module : Not applicable + // Is Play managed : No + @AsbSecurityTest(cveBugId = {242703460, 242703505, 242703780, 242704043, 243794204}) + @Test + public void testPocCVE_2022_20456() { + try { + mLongString = String.join("", Collections.nCopies(INPUT_STRING_LENGTH, "A")); + mComponentNameWithLongFields = new ComponentName(mLongString, mLongString); + mValidComponentName = new ComponentName(PACKAGE_NAME, CLASS_NAME); + mLongUri = Uri.parse("condition://" + mLongString); + mValidUri = Uri.parse(URI_STRING); + mViolations = new ArrayList<String>(); + + // Check AutomaticZenRule constructor + testIsConstructorVulnerable(); + + // Check AutomaticZenRule field setters + testIsFieldSetterVulnerable(); + + // Check AutomaticZenRule constructor using parcel input + testIsInputFromParcelVulnerable(); + + assertTrue("Device is vulnerable to at least one of the following vulnerabilities : " + + "b/242703460(CVE-2022-20489), b/242703505(CVE-2022-20490), b/242703780" + + "(CVE-2022-20456), b/242704043(CVE-2022-20492), b/243794204(CVE-2022-20494)" + + " due to these violations where input string length=" + INPUT_STRING_LENGTH + + " and input uri length=" + mLongUri.toString().length() + ":" + mViolations, + mViolations.isEmpty()); + } catch (Exception e) { + assumeNoException(e); + } + } +} diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java index 4e1b4afb3b3..8a4c0fc968d 100644 --- a/tests/tests/security/src/android/security/cts/StagefrightTest.java +++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java @@ -1808,6 +1808,12 @@ public class StagefrightTest extends StsExtraBusinessLogicTestCase { before any existing test methods ***********************************************************/ @Test + @AsbSecurityTest(cveBugId = 240971780) + public void testStagefright_cve_2022_33234() throws Exception { + doStagefrightTest(R.raw.cve_2022_33234); + } + + @Test @AsbSecurityTest(cveBugId = 235102508) public void testStagefright_cve_2022_25669() throws Exception { doStagefrightTest(R.raw.cve_2022_25669); diff --git a/tests/tests/security/src/android/security/cts/WorkSourceTest.java b/tests/tests/security/src/android/security/cts/WorkSourceTest.java new file mode 100644 index 00000000000..1438b29d1d6 --- /dev/null +++ b/tests/tests/security/src/android/security/cts/WorkSourceTest.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package android.security.cts; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import android.os.Parcel; +import android.os.WorkSource; +import android.platform.test.annotations.AsbSecurityTest; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class WorkSourceTest extends StsExtraBusinessLogicTestCase { + private static final int TEST_PID = 6512; + private static final String TEST_PACKAGE_NAME = "android.security.cts"; + + @Test + @AsbSecurityTest(cveBugId = 220302519) + public void testWorkChainParceling() { + WorkSource ws = new WorkSource(TEST_PID, TEST_PACKAGE_NAME); + // Create a WorkChain so the mChains becomes non-null + ws.createWorkChain(); + assertNotNull("WorkChains must be non-null in order to properly test parceling", + ws.getWorkChains()); + // Then clear it so it's an empty list. + ws.getWorkChains().clear(); + assertTrue("WorkChains must be empty in order to properly test parceling", + ws.getWorkChains().isEmpty()); + + Parcel p = Parcel.obtain(); + ws.writeToParcel(p, 0); + p.setDataPosition(0); + + // Read the Parcel back out and validate the two Parcels are identical + WorkSource readWs = WorkSource.CREATOR.createFromParcel(p); + assertNotNull(readWs.getWorkChains()); + assertTrue(readWs.getWorkChains().isEmpty()); + assertEquals(ws, readWs); + + // Assert that we've read every byte out of the Parcel. + assertEquals(p.dataSize(), p.dataPosition()); + + p.recycle(); + } +} |