1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.security.cts.CVE_2023_20917;
18 
19 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
20 
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assume.assumeNoException;
23 import static org.junit.Assume.assumeTrue;
24 
25 import android.app.Instrumentation;
26 import android.app.UiAutomation;
27 import android.content.BroadcastReceiver;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.IntentFilter;
31 import android.content.pm.UserInfo;
32 import android.net.Uri;
33 import android.os.UserHandle;
34 import android.os.UserManager;
35 
36 import androidx.test.runner.AndroidJUnit4;
37 import androidx.test.uiautomator.By;
38 import androidx.test.uiautomator.UiDevice;
39 import androidx.test.uiautomator.UiObject2;
40 import androidx.test.uiautomator.UiScrollable;
41 import androidx.test.uiautomator.UiSelector;
42 import androidx.test.uiautomator.Until;
43 
44 import org.junit.Test;
45 import org.junit.runner.RunWith;
46 
47 import java.util.List;
48 import java.util.concurrent.Semaphore;
49 import java.util.concurrent.TimeUnit;
50 import java.util.regex.Pattern;
51 
52 @RunWith(AndroidJUnit4.class)
53 public class DeviceTest {
54 
55     @Test
testCVE_2023_20917()56     public void testCVE_2023_20917() {
57         UiAutomation uiAutomation = null;
58         try {
59             final int waitMS = 5000;
60             Instrumentation instrumentation = getInstrumentation();
61             UiDevice device = UiDevice.getInstance(instrumentation);
62             Context context = instrumentation.getTargetContext();
63             uiAutomation = instrumentation.getUiAutomation();
64             Semaphore broadcastReceived = new Semaphore(0);
65 
66             // Register a broadcast receiver to receive broadcast from PocActivity indicating
67             // presence of vulnerability
68             BroadcastReceiver broadcastReceiver =
69                     new BroadcastReceiver() {
70                         @Override
71                         public void onReceive(Context context, Intent intent) {
72                             try {
73                                 if (intent.getAction()
74                                         .equals(context.getString(R.string.broadcastAction))) {
75                                     broadcastReceived.release();
76                                 }
77                             } catch (Exception ignored) {
78                                 // ignore any exceptions
79                             }
80                         }
81                     };
82 
83             UserHandle workUserHandle = null;
84             uiAutomation.adoptShellPermissionIdentity();
85             final List<UserInfo> list = context.getSystemService(UserManager.class).getUsers();
86             for (UserInfo info : list) {
87                 if (info.toString().contains(context.getString(R.string.workProfileName))) {
88                     workUserHandle = info.getUserHandle();
89                     break;
90                 }
91             }
92             assumeTrue(workUserHandle != null);
93 
94             context.startActivityAsUser(
95                     new Intent(context, WorkProfileActivity.class)
96                             .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
97                     workUserHandle);
98 
99             context.registerReceiver(
100                     broadcastReceiver,
101                     new IntentFilter(context.getString(R.string.broadcastAction)));
102 
103             final Intent intent = new Intent(Intent.ACTION_SEND);
104             intent.setData(Uri.parse(context.getString(R.string.contentUri)));
105             intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
106             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
107             Intent chooserIntent =
108                     Intent.createChooser(intent, context.getString(R.string.chooserMessage));
109             chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
110             context.startActivity(chooserIntent);
111 
112             Pattern workPattern =
113                     Pattern.compile(
114                             context.getString(R.string.workString), Pattern.CASE_INSENSITIVE);
115             assumeTrue(device.wait(Until.hasObject(By.text(workPattern)), waitMS));
116             UiObject2 workProfile = device.findObject(By.text(workPattern));
117             workProfile.click();
118             assumeTrue(workProfile.isSelected());
119 
120             UiScrollable uiScrollable =
121                     new UiScrollable(
122                             new UiSelector()
123                                     .resourceId(context.getString(R.string.contentPanelId)));
124             uiScrollable.setAsVerticalList();
125             uiScrollable.scrollForward();
126             uiScrollable.scrollTextIntoView(context.getString(R.string.cveId));
127 
128             // In the chooser activity UI, we need to select the 'CVE_2023_20917' App
129             // and not the individual activity that we have defined. Therefore, selecting
130             // the last instance
131             assumeTrue(
132                     device.wait(
133                             Until.hasObject(By.text(context.getString(R.string.cveId))), waitMS));
134             List<UiObject2> objects =
135                     device.findObjects(By.text(context.getString(R.string.cveId)));
136             objects.get(objects.size() - 1).click();
137 
138             // Whichever activity is at the bottom of the stack will suffer from the bug.
139             // Therefore, we are selecting the last instance in the stack.
140             assumeTrue(
141                     device.wait(
142                             Until.hasObject(By.text(context.getString(R.string.cveId))), waitMS));
143             List<UiObject2> objectsList =
144                     device.findObjects(By.text(context.getString(R.string.cveId)));
145             objectsList.get(objectsList.size() - 1).click();
146 
147             assertFalse(
148                     context.getString(R.string.testFailMessage),
149                     broadcastReceived.tryAcquire(waitMS, TimeUnit.MILLISECONDS));
150         } catch (Exception e) {
151             assumeNoException(e);
152         } finally {
153             try {
154                 uiAutomation.dropShellPermissionIdentity();
155             } catch (Exception ignored) {
156                 // ignore any exceptions
157             }
158         }
159     }
160 }
161