blob: f2bd770d085ac819eef28d886a2e1500429ba267 [file] [log] [blame]
Chalard Jean26aa91a2018-03-20 19:13:57 +09001/*
2 * Copyright (C) 2018 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
17package com.android.server.connectivity;
18
19import static android.Manifest.permission.CHANGE_NETWORK_STATE;
20import static android.Manifest.permission.CHANGE_WIFI_STATE;
21import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
22import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
23import static android.Manifest.permission.NETWORK_STACK;
paulhub6733802018-08-20 11:01:21 +080024import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_OEM;
25import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT;
26import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
Chalard Jean26aa91a2018-03-20 19:13:57 +090027import static android.content.pm.PackageManager.GET_PERMISSIONS;
paulhu3b0f5ea2018-11-01 10:38:11 +080028import static android.os.Process.SYSTEM_UID;
Chalard Jean26aa91a2018-03-20 19:13:57 +090029
junyulai2454b692018-11-01 17:16:31 +080030import static com.android.server.connectivity.PermissionMonitor.NETWORK;
31import static com.android.server.connectivity.PermissionMonitor.SYSTEM;
32
33import static junit.framework.Assert.fail;
34
Chalard Jean26aa91a2018-03-20 19:13:57 +090035import static org.junit.Assert.assertFalse;
36import static org.junit.Assert.assertTrue;
junyulai2454b692018-11-01 17:16:31 +080037import static org.mockito.ArgumentMatchers.any;
38import static org.mockito.Matchers.anyString;
Chalard Jean577164b2018-04-02 16:16:46 +090039import static org.mockito.Mockito.anyInt;
junyulai2454b692018-11-01 17:16:31 +080040import static org.mockito.Mockito.doAnswer;
junyulai345155e2018-11-09 12:37:16 +080041import static org.mockito.Mockito.doReturn;
Chalard Jean577164b2018-04-02 16:16:46 +090042import static org.mockito.Mockito.eq;
junyulai345155e2018-11-09 12:37:16 +080043import static org.mockito.Mockito.spy;
Chalard Jean26aa91a2018-03-20 19:13:57 +090044import static org.mockito.Mockito.when;
45
46import android.content.Context;
47import android.content.pm.ApplicationInfo;
48import android.content.pm.PackageInfo;
49import android.content.pm.PackageManager;
paulhub6733802018-08-20 11:01:21 +080050import android.os.Build;
junyulai2454b692018-11-01 17:16:31 +080051import android.os.INetworkManagementService;
52import android.os.UserHandle;
Chalard Jean26aa91a2018-03-20 19:13:57 +090053import android.support.test.filters.SmallTest;
54import android.support.test.runner.AndroidJUnit4;
55
56import org.junit.Before;
57import org.junit.Test;
58import org.junit.runner.RunWith;
59import org.mockito.Mock;
60import org.mockito.MockitoAnnotations;
junyulai2454b692018-11-01 17:16:31 +080061import org.mockito.invocation.InvocationOnMock;
62
63import java.util.HashMap;
Chalard Jean26aa91a2018-03-20 19:13:57 +090064
65@RunWith(AndroidJUnit4.class)
66@SmallTest
67public class PermissionMonitorTest {
junyulai2454b692018-11-01 17:16:31 +080068 private static final int MOCK_USER1 = 0;
69 private static final int MOCK_USER2 = 1;
70 private static final int MOCK_UID1 = 10001;
71 private static final String MOCK_PACKAGE1 = "appName1";
72 private static final String SYSTEM_PACKAGE1 = "sysName1";
73 private static final String SYSTEM_PACKAGE2 = "sysName2";
paulhub6733802018-08-20 11:01:21 +080074 private static final String PARTITION_SYSTEM = "system";
75 private static final String PARTITION_OEM = "oem";
76 private static final String PARTITION_PRODUCT = "product";
77 private static final String PARTITION_VENDOR = "vendor";
paulhu3b0f5ea2018-11-01 10:38:11 +080078 private static final int VERSION_P = Build.VERSION_CODES.P;
79 private static final int VERSION_Q = Build.VERSION_CODES.Q;
Chalard Jean26aa91a2018-03-20 19:13:57 +090080
81 @Mock private Context mContext;
82 @Mock private PackageManager mPackageManager;
junyulai2454b692018-11-01 17:16:31 +080083 @Mock private INetworkManagementService mNMS;
Chalard Jean26aa91a2018-03-20 19:13:57 +090084
85 private PermissionMonitor mPermissionMonitor;
86
87 @Before
88 public void setUp() throws Exception {
89 MockitoAnnotations.initMocks(this);
90 when(mContext.getPackageManager()).thenReturn(mPackageManager);
junyulai2454b692018-11-01 17:16:31 +080091 mPermissionMonitor = spy(new PermissionMonitor(mContext, mNMS));
Chalard Jean26aa91a2018-03-20 19:13:57 +090092 }
93
paulhu3b0f5ea2018-11-01 10:38:11 +080094 private boolean hasBgPermission(String partition, int targetSdkVersion, int uid,
95 String... permission) throws Exception {
96 final PackageInfo packageInfo = packageInfoWithPermissions(permission, partition);
paulhub6733802018-08-20 11:01:21 +080097 packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
paulhu3b0f5ea2018-11-01 10:38:11 +080098 packageInfo.applicationInfo.uid = uid;
Chalard Jean577164b2018-04-02 16:16:46 +090099 when(mPackageManager.getPackageInfoAsUser(
junyulai2454b692018-11-01 17:16:31 +0800100 eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
101 when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[] {MOCK_PACKAGE1});
paulhu3b0f5ea2018-11-01 10:38:11 +0800102 return mPermissionMonitor.hasUseBackgroundNetworksPermission(uid);
Chalard Jean26aa91a2018-03-20 19:13:57 +0900103 }
104
paulhub6733802018-08-20 11:01:21 +0800105 private PackageInfo packageInfoWithPermissions(String[] permissions, String partition) {
Chalard Jean26aa91a2018-03-20 19:13:57 +0900106 final PackageInfo packageInfo = new PackageInfo();
107 packageInfo.requestedPermissions = permissions;
108 packageInfo.applicationInfo = new ApplicationInfo();
paulhub6733802018-08-20 11:01:21 +0800109 int privateFlags = 0;
110 switch (partition) {
111 case PARTITION_OEM:
112 privateFlags = PRIVATE_FLAG_OEM;
113 break;
114 case PARTITION_PRODUCT:
115 privateFlags = PRIVATE_FLAG_PRODUCT;
116 break;
117 case PARTITION_VENDOR:
118 privateFlags = PRIVATE_FLAG_VENDOR;
119 break;
120 }
121 packageInfo.applicationInfo.privateFlags = privateFlags;
Chalard Jean26aa91a2018-03-20 19:13:57 +0900122 return packageInfo;
123 }
124
125 @Test
126 public void testHasPermission() {
paulhub6733802018-08-20 11:01:21 +0800127 PackageInfo app = packageInfoWithPermissions(new String[] {}, PARTITION_SYSTEM);
Chalard Jean26aa91a2018-03-20 19:13:57 +0900128 assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
129 assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
130 assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
131 assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
132
133 app = packageInfoWithPermissions(new String[] {
paulhub6733802018-08-20 11:01:21 +0800134 CHANGE_NETWORK_STATE, NETWORK_STACK
135 }, PARTITION_SYSTEM);
Chalard Jean26aa91a2018-03-20 19:13:57 +0900136 assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
137 assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
138 assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
139 assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
140
141 app = packageInfoWithPermissions(new String[] {
paulhub6733802018-08-20 11:01:21 +0800142 CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL
143 }, PARTITION_SYSTEM);
Chalard Jean26aa91a2018-03-20 19:13:57 +0900144 assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
145 assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
146 assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
147 assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
148 }
149
150 @Test
paulhub6733802018-08-20 11:01:21 +0800151 public void testIsVendorApp() {
152 PackageInfo app = packageInfoWithPermissions(new String[] {}, PARTITION_SYSTEM);
153 assertFalse(mPermissionMonitor.isVendorApp(app.applicationInfo));
154 app = packageInfoWithPermissions(new String[] {}, PARTITION_OEM);
155 assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
156 app = packageInfoWithPermissions(new String[] {}, PARTITION_PRODUCT);
157 assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
158 app = packageInfoWithPermissions(new String[] {}, PARTITION_VENDOR);
159 assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
Chalard Jean26aa91a2018-03-20 19:13:57 +0900160 }
161
162 @Test
163 public void testHasUseBackgroundNetworksPermission() throws Exception {
junyulai2454b692018-11-01 17:16:31 +0800164 assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
165 assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
166 assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, NETWORK_STACK));
167 assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
168 assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1,
paulhu3b0f5ea2018-11-01 10:38:11 +0800169 CONNECTIVITY_USE_RESTRICTED_NETWORKS));
junyulai2454b692018-11-01 17:16:31 +0800170 assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
Chalard Jean26aa91a2018-03-20 19:13:57 +0900171
junyulai2454b692018-11-01 17:16:31 +0800172 assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
173 assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE));
paulhu3b0f5ea2018-11-01 10:38:11 +0800174 }
Chalard Jean26aa91a2018-03-20 19:13:57 +0900175
paulhu3b0f5ea2018-11-01 10:38:11 +0800176 @Test
177 public void testHasUseBackgroundNetworksPermissionSystemUid() throws Exception {
junyulai345155e2018-11-09 12:37:16 +0800178 doReturn(VERSION_P).when(mPermissionMonitor).getDeviceFirstSdkInt();
paulhu3b0f5ea2018-11-01 10:38:11 +0800179 assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
180 assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CHANGE_WIFI_STATE));
181 assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID,
182 CONNECTIVITY_USE_RESTRICTED_NETWORKS));
Chalard Jean26aa91a2018-03-20 19:13:57 +0900183
junyulai345155e2018-11-09 12:37:16 +0800184 doReturn(VERSION_Q).when(mPermissionMonitor).getDeviceFirstSdkInt();
paulhu3b0f5ea2018-11-01 10:38:11 +0800185 assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
186 assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CHANGE_WIFI_STATE));
187 assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID,
188 CONNECTIVITY_USE_RESTRICTED_NETWORKS));
189 }
190
191 @Test
192 public void testHasUseBackgroundNetworksPermissionVendorApp() throws Exception {
junyulai2454b692018-11-01 17:16:31 +0800193 assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
194 assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
195 assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, NETWORK_STACK));
196 assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
197 assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1,
paulhu3b0f5ea2018-11-01 10:38:11 +0800198 CONNECTIVITY_USE_RESTRICTED_NETWORKS));
junyulai2454b692018-11-01 17:16:31 +0800199 assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
paulhu3b0f5ea2018-11-01 10:38:11 +0800200
junyulai2454b692018-11-01 17:16:31 +0800201 assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
202 assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE));
203 }
204
205 private class NMSMonitor {
206 private final HashMap<Integer, Boolean> mApps = new HashMap<>();
207
208 NMSMonitor(INetworkManagementService mockNMS) throws Exception {
209 // Add hook to verify and track result of setPermission.
210 doAnswer((InvocationOnMock invocation) -> {
211 final Object[] args = invocation.getArguments();
212 final Boolean isSystem = args[0].equals("SYSTEM");
213 for (final int uid : (int[]) args[1]) {
214 // TODO: Currently, permission monitor will send duplicate commands for each uid
215 // corresponding to each user. Need to fix that and uncomment below test.
216 // if (mApps.containsKey(uid) && mApps.get(uid) == isSystem) {
217 // fail("uid " + uid + " is already set to " + isSystem);
218 // }
219 mApps.put(uid, isSystem);
220 }
221 return null;
222 }).when(mockNMS).setPermission(anyString(), any(int[].class));
223
224 // Add hook to verify and track result of clearPermission.
225 doAnswer((InvocationOnMock invocation) -> {
226 final Object[] args = invocation.getArguments();
227 for (final int uid : (int[]) args[0]) {
228 // TODO: Currently, permission monitor will send duplicate commands for each uid
229 // corresponding to each user. Need to fix that and uncomment below test.
230 // if (!mApps.containsKey(uid)) {
231 // fail("uid " + uid + " does not exist.");
232 // }
233 mApps.remove(uid);
234 }
235 return null;
236 }).when(mockNMS).clearPermission(any(int[].class));
237 }
238
239 public void expectPermission(Boolean permission, int[] users, int[] apps) {
240 for (final int user : users) {
241 for (final int app : apps) {
242 final int uid = UserHandle.getUid(user, app);
243 if (!mApps.containsKey(uid)) {
244 fail("uid " + uid + " does not exist.");
245 }
246 if (mApps.get(uid) != permission) {
247 fail("uid " + uid + " has wrong permission: " + permission);
248 }
249 }
250 }
251 }
252
253 public void expectNoPermission(int[] users, int[] apps) {
254 for (final int user : users) {
255 for (final int app : apps) {
256 final int uid = UserHandle.getUid(user, app);
257 if (mApps.containsKey(uid)) {
258 fail("uid " + uid + " has listed permissions, expected none.");
259 }
260 }
261 }
262 }
263 }
264
265 @Test
266 public void testUserAndPackageAddRemove() throws Exception {
267 final NMSMonitor mNMSMonitor = new NMSMonitor(mNMS);
268
269 // MOCK_UID1: MOCK_PACKAGE1 only has network permission.
270 // SYSTEM_UID: SYSTEM_PACKAGE1 has system permission.
271 // SYSTEM_UID: SYSTEM_PACKAGE2 only has network permission.
272 doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(eq(SYSTEM), anyString());
273 doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(any(),
274 eq(SYSTEM_PACKAGE1));
275 doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
276 eq(SYSTEM_PACKAGE2));
277 doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
278 eq(MOCK_PACKAGE1));
279
280 // Add SYSTEM_PACKAGE2, expect only have network permission.
281 mPermissionMonitor.onUserAdded(MOCK_USER1);
282 addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_UID);
283 mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID});
284
285 // Add SYSTEM_PACKAGE1, expect permission escalate.
286 addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_UID);
287 mNMSMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID});
288
289 mPermissionMonitor.onUserAdded(MOCK_USER2);
290 mNMSMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2},
291 new int[]{SYSTEM_UID});
292
293 addPackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
294 mNMSMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2},
295 new int[]{SYSTEM_UID});
296 mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
297 new int[]{MOCK_UID1});
298
299 // Remove MOCK_UID1, expect no permission left for all user.
300 mPermissionMonitor.onPackageRemoved(MOCK_UID1);
301 removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_UID1);
302 mNMSMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{MOCK_UID1});
303
304 // Remove SYSTEM_PACKAGE1, expect permission downgrade.
305 when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{SYSTEM_PACKAGE2});
306 removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, SYSTEM_UID);
307 mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
308 new int[]{SYSTEM_UID});
309
310 mPermissionMonitor.onUserRemoved(MOCK_USER1);
311 mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER2}, new int[]{SYSTEM_UID});
312
313 // Remove all packages, expect no permission left.
314 when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{});
315 removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_UID);
316 mNMSMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
317 new int[]{SYSTEM_UID, MOCK_UID1});
318
319 // Remove last user, expect no redundant clearPermission is invoked.
320 mPermissionMonitor.onUserRemoved(MOCK_USER2);
321 mNMSMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
322 new int[]{SYSTEM_UID, MOCK_UID1});
323 }
324
325 // Normal package add/remove operations will trigger multiple intent for uids corresponding to
326 // each user. To simulate generic package operations, the onPackageAdded/Removed will need to be
327 // called multiple times with the uid corresponding to each user.
328 private void addPackageForUsers(int[] users, String packageName, int uid) {
329 for (final int user : users) {
330 mPermissionMonitor.onPackageAdded(packageName, UserHandle.getUid(user, uid));
331 }
332 }
333
334 private void removePackageForUsers(int[] users, int uid) {
335 for (final int user : users) {
336 mPermissionMonitor.onPackageRemoved(UserHandle.getUid(user, uid));
337 }
Chalard Jean26aa91a2018-03-20 19:13:57 +0900338 }
339}