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