Updated CTS test for Android Security b/194695497 Bug: 194695497 Bug: 206513471 Test: Ran the new testcase on android-12.0.0_r1 with/without patch Change-Id: I0c761f90717188c623a4fbc492e0d1a130c18853
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp index d3e2302..2f87b9c 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp
@@ -30,10 +30,10 @@ test_suites: [ "sts", ], - sdk_version: "current", static_libs: [ "androidx.test.core", "androidx.test.rules", "androidx.test.uiautomator_uiautomator", ], + platform_apis: true, }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml index f097825..74e263c 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml
@@ -22,12 +22,8 @@ <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/> <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/> - <application - android:testOnly="true" - android:label="CVE-2021-39626" - android:supportsRtl="true"> - <activity - android:name=".PocActivity" + <application> + <activity android:name=".PocActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -35,7 +31,6 @@ </intent-filter> </activity> </application> - <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="android.security.cts.CVE_2021_39626" />
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/integers.xml new file mode 100644 index 0000000..d5ae744 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/integers.xml
@@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2022 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources> + <integer name="assumptionFailure">-1</integer> + <integer name="pass">0</integer> + <integer name="enabled">1</integer> + <integer name="disabled">2</integer> +</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/strings.xml new file mode 100644 index 0000000..e6f53e7 --- /dev/null +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/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> + <string name="allowButtonResName">android:id/button1</string> + <string name="btAction">btAction</string> + <string name="className">.Settings$ConnectedDeviceDashboardActivity</string> + <string name="defaultSemaphoreMsg">Could not get message key in shared preferences</string> + <string name="defaultSettingsPkg">com.android.settings</string> + <string name="failMessage">Vulnerable to b/194695497 !!</string> + <string name="messageKey">message</string> + <string name="resultKey">result</string> + <string name="sharedPreferences">CVE_2021_39626_prefs</string> +</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java index cd24540..6bb8d16 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java
@@ -18,14 +18,15 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assume.assumeNoException; -import static org.junit.Assume.assumeNotNull; import static org.junit.Assume.assumeTrue; import android.bluetooth.BluetoothAdapter; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.pm.PackageManager; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.content.res.Resources; import android.provider.Settings; import androidx.test.InstrumentationRegistry; @@ -34,69 +35,121 @@ 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.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + @RunWith(AndroidJUnit4.class) public class DeviceTest { - private static final int TIMEOUT = 5000; - private static Context context; + static final int TIMEOUT = 10000; + boolean mBtState = false; + BluetoothAdapter mBtAdapter; + Context mContext; + OnSharedPreferenceChangeListener mListener; + Resources mResources; + SharedPreferences mSharedPrefs; + Semaphore mPreferenceChanged; + UiDevice mDevice; - private static String getSettingsPkgName() { + private String getSettingsPkgName() { Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS); ComponentName settingsComponent = - settingsIntent.resolveActivity(context.getPackageManager()); + settingsIntent.resolveActivity(mContext.getPackageManager()); String pkgName = settingsComponent != null ? settingsComponent.getPackageName() - : "com.android.settings"; - assumeNotNull(pkgName); + : mContext.getString(R.string.defaultSettingsPkg); return pkgName; } - private void openApplication(String applicationName) { - Intent intent = context.getPackageManager().getLaunchIntentForPackage(applicationName); - assumeNotNull(intent); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + @After + public void tearDown() { try { - context.startActivity(intent); + // Disable bluetooth if it was OFF before the test + if (!mBtState) { + Intent intent = new Intent(mContext, PocActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(mContext.getString(R.string.btAction), + BluetoothAdapter.ACTION_REQUEST_DISABLE); + mContext.startActivity(intent); + } + mPreferenceChanged = new Semaphore(0); + mPreferenceChanged.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS); + int result = mSharedPrefs.getInt(mResources.getString(R.string.resultKey), + mResources.getInteger(R.integer.assumptionFailure)); + String message = mSharedPrefs.getString(mResources.getString(R.string.messageKey), + mResources.getString(R.string.defaultSemaphoreMsg)); + + // Go to home screen + mDevice.pressHome(); } catch (Exception e) { - assumeNoException(e); + // ignore the exception } } @Test public void testBtDiscoverable() { - // Initialize UiDevice instance - UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); - context = InstrumentationRegistry.getInstrumentation().getContext(); - BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter(); - assumeNotNull(btAdapter); + try { + // Initialize UiDevice instance + mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + mContext = InstrumentationRegistry.getInstrumentation().getContext(); + mBtAdapter = BluetoothAdapter.getDefaultAdapter(); - // Save the state of bluetooth adapter to reset after the test - boolean btState = btAdapter.isEnabled(); - if (!btState) { - // If bluetooth is disabled, enable it and wait for adapter startup to complete - assumeTrue(btAdapter.enable()); - try { - Thread.sleep(TIMEOUT); - } catch (Exception e) { - assumeNoException(e); - } + // Save the state of bluetooth adapter to reset after the test + mBtState = mBtAdapter.isEnabled(); + + // If bluetooth is disabled, enable it and wait for start activity to complete + Intent intent = new Intent(mContext, PocActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(mContext.getString(R.string.btAction), + BluetoothAdapter.ACTION_REQUEST_ENABLE); + mContext.startActivity(intent); + mResources = mContext.getResources(); + + mSharedPrefs = mContext.getSharedPreferences( + mResources.getString(R.string.sharedPreferences), Context.MODE_APPEND); + mPreferenceChanged = new Semaphore(0); + mListener = new OnSharedPreferenceChangeListener() { + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + if (key.equals(mResources.getString(R.string.resultKey))) { + mPreferenceChanged.release(); + } + } + }; + mSharedPrefs.registerOnSharedPreferenceChangeListener(mListener); + mPreferenceChanged.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS); + + int result = mSharedPrefs.getInt(mResources.getString(R.string.resultKey), + mResources.getInteger(R.integer.assumptionFailure)); + String message = mSharedPrefs.getString(mResources.getString(R.string.messageKey), + mResources.getString(R.string.defaultSemaphoreMsg)); + assumeTrue(message, result != mResources.getInteger(R.integer.assumptionFailure)); + + // Checking if bluetooth is enabled. The test requires bluetooth to be enabled, + // assumption failing the test if it's not enabled + assumeTrue(mBtAdapter.isEnabled()); + + // Launch bluetooth settings which is supposed to set scan mode to + // SCAN_MODE_CONNECTABLE_DISCOVERABLE if vulnerability is active + intent = new Intent(); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + String settingsPkg = getSettingsPkgName(); + intent.setClassName(settingsPkg, settingsPkg + mContext.getString(R.string.className)); + mContext.startActivity(intent); + + assumeTrue(mDevice.wait(Until.hasObject(By.pkg(settingsPkg)), TIMEOUT)); + + boolean isBtDiscoverable = false; + isBtDiscoverable = + (mBtAdapter.getScanMode() == mBtAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE); + + // The test fails if bluetooth is made discoverable through PoC + assertFalse(mContext.getString(R.string.failMessage), isBtDiscoverable); + } catch (Exception e) { + assumeNoException(e); } - assumeTrue(btAdapter.isEnabled()); - - // Launch the PoC application and ensure that it launches bluetooth settings - openApplication(context.getPackageName()); - assumeTrue(device.wait(Until.hasObject(By.pkg(getSettingsPkgName())), TIMEOUT)); - - boolean isBtDiscoverable = - (btAdapter.getScanMode() == btAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE); - - // Disable bluetooth if it was OFF before the test - if (!btState) { - btAdapter.disable(); - } - - // The test fails if bluetooth is made discoverable through PoC - assertFalse("Vulnerable to b/194695497 !!", isBtDiscoverable); } }
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java index d4425ff..9a43cd1 100644 --- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java +++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java
@@ -16,24 +16,88 @@ package android.security.cts.CVE_2021_39626; -import static org.junit.Assume.assumeNoException; - import android.app.Activity; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothManager; +import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; -import android.provider.Settings; + +import androidx.annotation.IntegerRes; +import androidx.test.InstrumentationRegistry; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject2; +import androidx.test.uiautomator.Until; public class PocActivity extends Activity { + private static final int TIMEOUT = 5000; + private static final int REQUEST_ENABLE_BT = 1; + private static final int REQUEST_DISABLE_BT = 2; + + int getInteger(@IntegerRes int resId) { + return getResources().getInteger(resId); + } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Intent intent = new Intent(); - intent.setAction(Settings.ACTION_BLUETOOTH_SETTINGS); try { - startActivity(intent); + String action = getIntent().getStringExtra(getString(R.string.btAction)); + UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + BluetoothManager bluetoothManager = getSystemService(BluetoothManager.class); + BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter(); + int code = REQUEST_ENABLE_BT; + if (action.equals(BluetoothAdapter.ACTION_REQUEST_DISABLE)) { + code = REQUEST_DISABLE_BT; + } + + if ((action.equals(BluetoothAdapter.ACTION_REQUEST_ENABLE) + && !bluetoothAdapter.isEnabled()) + || (action.equals(BluetoothAdapter.ACTION_REQUEST_DISABLE) + && bluetoothAdapter.isEnabled())) { + Intent enableBtIntent = new Intent(action); + startActivityForResult(enableBtIntent, code); + + // Wait for the activity to appear and the allow button + device.wait(Until.hasObject(By.res(getString(R.string.allowButtonResName))), + TIMEOUT); + + // Click on the allow button + UiObject2 object = + device.findObject(By.res(getString(R.string.allowButtonResName))); + object.click(); + } else { + sendTestResult(getInteger(R.integer.pass), ""); + finish(); + return; + } } catch (Exception e) { - assumeNoException(e); + sendTestResult(getInteger(R.integer.assumptionFailure), e.getMessage()); + return; + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_OK) { + finish(); + sendTestResult(getInteger(R.integer.enabled), ""); + } else if (requestCode == REQUEST_DISABLE_BT && resultCode == Activity.RESULT_OK) { + finish(); + sendTestResult(getInteger(R.integer.disabled), ""); + } + } + + private void sendTestResult(int result, String message) { + SharedPreferences sh = + getSharedPreferences(getString(R.string.sharedPreferences), Context.MODE_PRIVATE); + if (sh != null) { + SharedPreferences.Editor edit = sh.edit(); + edit.putInt(getString(R.string.resultKey), result); + edit.putString(getString(R.string.messageKey), message); + edit.commit(); } } }