1 /*
2  * Copyright (C) 2022 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.AutomaticZenRuleTests;
18 
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assume.assumeNoException;
21 import static org.junit.Assume.assumeTrue;
22 
23 import android.app.AutomaticZenRule;
24 import android.app.Instrumentation;
25 import android.app.NotificationManager;
26 import android.app.UiAutomation;
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.net.Uri;
30 import android.platform.test.annotations.AsbSecurityTest;
31 import androidx.test.InstrumentationRegistry;
32 import androidx.test.runner.AndroidJUnit4;
33 
34 import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
35 
36 import org.junit.After;
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 
41 import java.util.ArrayList;
42 
43 @RunWith(AndroidJUnit4.class)
44 public class AutomaticZenRuleTests extends StsExtraBusinessLogicTestCase {
45     private static final String URI_STRING = "condition://android";
46     private static final String ZEN_RULE_NAME = "ZenRuleName";
47     private boolean mNotificationPolicyAccessGranted = false;
48     private NotificationManager mNotificationManager = null;
49     private String mPackageName = null;
50     private UiAutomation mUiautomation = null;
51 
52     @Before
setUp()53     public void setUp() {
54         try {
55             final int timeoutDuration = 5000;
56             final int waitDuration = 100;
57             Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
58             Context context = instrumentation.getContext();
59             mNotificationManager = context.getSystemService(NotificationManager.class);
60             mPackageName = context.getPackageName();
61             mUiautomation = instrumentation.getUiAutomation();
62             mUiautomation.executeShellCommand("cmd notification allow_dnd " + mPackageName);
63             long startTime = System.currentTimeMillis();
64             while (System.currentTimeMillis() - startTime < timeoutDuration) {
65                 // Busy wait until notification policy access is granted
66                 if (mNotificationManager.isNotificationPolicyAccessGranted()) {
67                     mNotificationPolicyAccessGranted = true;
68                     break;
69                 }
70                 Thread.sleep(waitDuration);
71             }
72             assumeTrue("Notification policy access not granted", mNotificationPolicyAccessGranted);
73         } catch (Exception e) {
74             assumeNoException(e);
75         }
76     }
77 
78     @After
tearDown()79     public void tearDown() {
80         try {
81             mUiautomation.executeShellCommand("cmd notification disallow_dnd " + mPackageName);
82         } catch (Exception ignoredException) {
83             // Ignoring exceptions
84         }
85     }
86 
testUsingAppComponents(ComponentName owner, ComponentName components[])87     private boolean testUsingAppComponents(ComponentName owner, ComponentName components[]) {
88         int automaticZenRules = 0;
89         boolean isVulnerable = true;
90         final int ruleLimitPerPackage = (components != null && components.length > 1) ? 60 : 200;
91         ArrayList<String> ruleIds = new ArrayList<>();
92         try {
93             // Storing the number of automaticZenRules present before test run
94             automaticZenRules = mNotificationManager.getAutomaticZenRules().size();
95 
96             for (int i = 0; i < ruleLimitPerPackage; ++i) {
97                 if (components != null) {
98                     for (int j = 0; j < components.length; ++j) {
99                         int ruleNo = i * components.length + j;
100                         Uri conditionId = Uri.parse(URI_STRING + ruleNo);
101                         AutomaticZenRule rule = new AutomaticZenRule(ZEN_RULE_NAME + ruleNo, owner,
102                                 components[j], conditionId, null,
103                                 NotificationManager.INTERRUPTION_FILTER_ALL, true);
104                         String id = mNotificationManager.addAutomaticZenRule(rule);
105                         ruleIds.add(id);
106                     }
107                 } else {
108                     Uri conditionId = Uri.parse(URI_STRING + i);
109                     AutomaticZenRule rule = new AutomaticZenRule(ZEN_RULE_NAME + i, owner, null,
110                             conditionId, null, NotificationManager.INTERRUPTION_FILTER_ALL, true);
111                     String id = mNotificationManager.addAutomaticZenRule(rule);
112                     ruleIds.add(id);
113                 }
114             }
115         } catch (Exception e) {
116             isVulnerable = false;
117             if (!(e instanceof IllegalArgumentException)) {
118                 assumeNoException(e);
119             }
120         } finally {
121             try {
122                 if (mNotificationPolicyAccessGranted) {
123                     // Retrieving the total number of automaticZenRules added by test so that the
124                     // test fails only if all automaticZenRules were added successfully
125                     automaticZenRules =
126                             mNotificationManager.getAutomaticZenRules().size() - automaticZenRules;
127                     for (String id : ruleIds) {
128                         mNotificationManager.removeAutomaticZenRule(id);
129                     }
130                 }
131                 int ruleLimitPerPackageTotal =
132                         components != null ? ruleLimitPerPackage * components.length
133                                 : ruleLimitPerPackage;
134                 boolean allZenRulesAdded = ruleLimitPerPackageTotal == automaticZenRules;
135                 isVulnerable = (isVulnerable && allZenRulesAdded);
136             } catch (Exception ignoredException) {
137                 // Ignoring exceptions
138             }
139         }
140         return isVulnerable;
141     }
142 
143     // b/220735360
144     // Vulnerable library : framework.jar
145     // Vulnerable module : Not applicable
146     // Is Play managed : No
147     @AsbSecurityTest(cveBugId = 220735360)
148     @Test
testPocCVE_2022_20143()149     public void testPocCVE_2022_20143() {
150         try {
151             ComponentName appComponent =
152                     new ComponentName(mPackageName, PocActivity.class.getCanonicalName());
153             ComponentName[] components = {appComponent};
154             boolean testUsingAppSingleComponentStatus = testUsingAppComponents(null, components);
155             assertFalse("Device is vulnerable to b/220735360!! System can be corrupted by adding"
156                     + " many automaticZenRules via NotificationManager#addAutomaticZenRule."
157                     + " Note: Device also seems to be vulnerable to b/235823407 and"
158                     + " b/242537431", testUsingAppSingleComponentStatus);
159         } catch (Exception e) {
160             assumeNoException(e);
161         }
162     }
163 
164     // b/235823407
165     // Vulnerable library : framework.jar
166     // Vulnerable module : Not applicable
167     // Is Play managed : No
168     @AsbSecurityTest(cveBugId = 235823407)
169     @Test
testPocCVE_2022_20425()170     public void testPocCVE_2022_20425() {
171         try {
172             ComponentName firstConfigurationActivity =
173                     new ComponentName(mPackageName, PocActivity.class.getCanonicalName());
174             ComponentName secondConfigurationActivity =
175                     new ComponentName(mPackageName, SecondPocActivity.class.getCanonicalName());
176             ComponentName[] components = {firstConfigurationActivity, secondConfigurationActivity};
177             boolean testUsingAppMultipleComponentStatus = testUsingAppComponents(null, components);
178             assertFalse(
179                     "Device is vulnerable to b/235823407!! Bypass fix of CVE-2022-20143:"
180                             + " Bypass zen rule limit with different configuration Activity"
181                             + " Note: Device also seems to be vulnerable to b/242537431",
182                     testUsingAppMultipleComponentStatus);
183         } catch (Exception e) {
184             assumeNoException(e);
185         }
186     }
187 
188     // b/242537431
189     // Vulnerable library : framework.jar
190     // Vulnerable module : Not applicable
191     // Is Play managed : No
192     @AsbSecurityTest(cveBugId = 242537431)
193     @Test
testPocCVE_2022_20455()194     public void testPocCVE_2022_20455() {
195         try {
196             ComponentName systemComponent =
197                     new ComponentName("android", "ScheduleConditionProvider");
198             boolean testUsingSystemComponentStatus = testUsingAppComponents(systemComponent, null);
199             assertFalse(
200                     "Device is vulnerable to b/242537431!! System can be corrupted by adding"
201                             + " many automaticZenRules via NotificationManager#addAutomaticZenRule",
202                     testUsingSystemComponentStatus);
203         } catch (Exception e) {
204             assumeNoException(e);
205         }
206     }
207 }
208