1 /*
2  * Copyright (C) 2024 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_2024_0024;
18 
19 import static android.Manifest.permission.CREATE_USERS;
20 import static android.os.Environment.buildPath;
21 
22 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
23 
24 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
25 import static com.android.sts.common.SystemUtil.poll;
26 
27 import static com.google.common.truth.Truth.assertWithMessage;
28 import static com.google.common.truth.TruthJUnit.assume;
29 
30 import android.app.Instrumentation;
31 import android.content.BroadcastReceiver;
32 import android.content.Context;
33 import android.content.Intent;
34 import android.content.IntentFilter;
35 import android.content.pm.UserInfo;
36 import android.os.Build;
37 import android.os.Environment;
38 import android.os.UserManager;
39 import android.platform.test.annotations.AsbSecurityTest;
40 import android.security.cts.R;
41 import android.support.test.uiautomator.By;
42 import android.support.test.uiautomator.BySelector;
43 import android.support.test.uiautomator.UiDevice;
44 import android.support.test.uiautomator.Until;
45 
46 import androidx.test.runner.AndroidJUnit4;
47 
48 import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
49 
50 import org.junit.Test;
51 import org.junit.runner.RunWith;
52 
53 import java.util.List;
54 import java.util.concurrent.CompletableFuture;
55 import java.util.concurrent.TimeUnit;
56 import java.util.regex.Pattern;
57 
58 @RunWith(AndroidJUnit4.class)
59 public class CVE_2024_0024 extends StsExtraBusinessLogicTestCase {
60     private static final int MAX_UNSIGNED_SHORT = (1 << 16) - 1;
61     UserManager mUserManager = null;
62     UserInfo mUserInfo = null;
63 
64     @AsbSecurityTest(cveBugId = 293602317)
65     @Test
grantSmsPermission()66     public void grantSmsPermission() {
67         try {
68             final Instrumentation instrumentation = getInstrumentation();
69             final Context context = instrumentation.getContext();
70             mUserManager = context.getSystemService(UserManager.class);
71 
72             // Check if the device supports multiple users
73             assume().withMessage("This device does not support multiple users")
74                     .that(mUserManager.supportsMultipleUsers())
75                     .isTrue();
76 
77             // Launch pocActivity
78             context.startActivity(
79                     new Intent(context, PocActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
80 
81             // Fetch and add the flag 'RECEIVER_NOT_EXPORTED' for 'TIRAMISU' and above versions to
82             // keep the code consistent
83             final int requiredFlag =
84                     Build.VERSION.SDK_INT >= 33 /* TIRAMISU */
85                             ? (int) Context.class.getField("RECEIVER_NOT_EXPORTED").get(context)
86                             : 0;
87 
88             // Check if there is an exception while calling vulnerable function in PocActivity
89             // Register a broadcast receiver to get broadcast from PocActivity
90             CompletableFuture<String> broadcastReceived = new CompletableFuture<String>();
91             context.registerReceiver(
92                     new BroadcastReceiver() {
93                         @Override
94                         public void onReceive(Context context, Intent intent) {
95                             try {
96                                 broadcastReceived.complete(
97                                         intent.getStringExtra(
98                                                 context.getString(
99                                                         R.string.CVE_2024_0024_exception)));
100                             } catch (Exception e) {
101                                 // Ignore exceptions here
102                             }
103                         }
104                     },
105                     new IntentFilter(context.getString(R.string.CVE_2024_0024_action)),
106                     requiredFlag);
107 
108             // Wait for broadcast from PocActivity
109             String exception = broadcastReceived.get(10_000L /* timeout */, TimeUnit.MILLISECONDS);
110             assume().withMessage("Exception occurred in PocActivity " + exception)
111                     .that(exception)
112                     .isNull();
113 
114             // Click ok
115             UiDevice uiDevice = UiDevice.getInstance(instrumentation);
116             BySelector okButtonSelector = By.text(Pattern.compile("ok", Pattern.CASE_INSENSITIVE));
117             uiDevice.wait(Until.hasObject(okButtonSelector), 5_000L /* timeout */);
118             uiDevice.findObject(okButtonSelector).click();
119 
120             // Poll till user CVE_2024_0024_user is created and get it's user info
121             assume().withMessage("CVE_2024_0024_user was not found")
122                     .that(
123                             poll(
124                                     () -> {
125                                         return runWithShellPermissionIdentity(
126                                                 () -> {
127                                                     final List<UserInfo> list =
128                                                             mUserManager.getUsers();
129                                                     for (UserInfo info : list) {
130                                                         if (info.name.contains(
131                                                                 "CVE_2024_0024_user")) {
132                                                             mUserInfo = info;
133                                                             return true;
134                                                         }
135                                                     }
136                                                     return false;
137                                                 },
138                                                 CREATE_USERS);
139                                     }))
140                     .isTrue();
141 
142             assume().withMessage("Unable to get created user's info").that(mUserInfo).isNotNull();
143             assertWithMessage(
144                             "Device is vulnerable to b/293602317 !!"
145                                     + " Create and persist a new secondary user without any"
146                                     + " restrictions via a super large accountType")
147                     .that(
148                             poll(
149                                     () -> {
150                                         return (buildPath(
151                                                                 Environment
152                                                                         .getDataSystemDirectory(),
153                                                                 "users",
154                                                                 mUserInfo.id + ".xml")
155                                                         .length()
156                                                 > MAX_UNSIGNED_SHORT - 1);
157                                     }))
158                     .isFalse();
159         } catch (Exception e) {
160             assume().that(e).isNull();
161         } finally {
162             try {
163                 mUserManager.removeUser(mUserInfo.id);
164             } catch (Exception ignore) {
165                 // Ignore unintended exceptions
166             }
167         }
168     }
169 }
170