blob: 62a471896579343f42981ea7ccadb4a4fb1ff29a [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;
Chenbo Feng436fe582019-02-25 22:55:58 -080023import static android.Manifest.permission.INTERNET;
Chalard Jean26aa91a2018-03-20 19:13:57 +090024import static android.Manifest.permission.NETWORK_STACK;
Chenbo Feng436fe582019-02-25 22:55:58 -080025import static android.Manifest.permission.UPDATE_DEVICE_STATS;
paulhub6733802018-08-20 11:01:21 +080026import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_OEM;
27import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT;
28import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
Chenbo Feng436fe582019-02-25 22:55:58 -080029import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
Chalard Jean26aa91a2018-03-20 19:13:57 +090030import static android.content.pm.PackageManager.GET_PERMISSIONS;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000031import static android.content.pm.PackageManager.MATCH_ANY_USER;
paulhu3b0f5ea2018-11-01 10:38:11 +080032import static android.os.Process.SYSTEM_UID;
Chalard Jean26aa91a2018-03-20 19:13:57 +090033
junyulai2454b692018-11-01 17:16:31 +080034import static com.android.server.connectivity.PermissionMonitor.NETWORK;
35import static com.android.server.connectivity.PermissionMonitor.SYSTEM;
36
37import static junit.framework.Assert.fail;
38
Chalard Jean26aa91a2018-03-20 19:13:57 +090039import static org.junit.Assert.assertFalse;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000040import static org.junit.Assert.assertNull;
Chalard Jean26aa91a2018-03-20 19:13:57 +090041import static org.junit.Assert.assertTrue;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000042import static org.mockito.AdditionalMatchers.aryEq;
junyulai2454b692018-11-01 17:16:31 +080043import static org.mockito.ArgumentMatchers.any;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000044import static org.mockito.ArgumentMatchers.anyInt;
45import static org.mockito.ArgumentMatchers.anyString;
46import static org.mockito.ArgumentMatchers.eq;
junyulai2454b692018-11-01 17:16:31 +080047import static org.mockito.Mockito.doAnswer;
junyulai345155e2018-11-09 12:37:16 +080048import static org.mockito.Mockito.doReturn;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000049import static org.mockito.Mockito.reset;
junyulai345155e2018-11-09 12:37:16 +080050import static org.mockito.Mockito.spy;
Chenbo Feng436fe582019-02-25 22:55:58 -080051import static org.mockito.Mockito.verify;
Chalard Jean26aa91a2018-03-20 19:13:57 +090052import static org.mockito.Mockito.when;
53
54import android.content.Context;
55import android.content.pm.ApplicationInfo;
56import android.content.pm.PackageInfo;
Chenbo Feng436fe582019-02-25 22:55:58 -080057import android.content.pm.PackageList;
Chalard Jean26aa91a2018-03-20 19:13:57 +090058import android.content.pm.PackageManager;
Chenbo Feng436fe582019-02-25 22:55:58 -080059import android.content.pm.PackageManagerInternal;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000060import android.content.pm.UserInfo;
Chenbo Feng436fe582019-02-25 22:55:58 -080061import android.net.INetd;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000062import android.net.UidRange;
paulhub6733802018-08-20 11:01:21 +080063import android.os.Build;
junyulai2454b692018-11-01 17:16:31 +080064import android.os.UserHandle;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000065import android.os.UserManager;
Chenbo Feng436fe582019-02-25 22:55:58 -080066import android.util.SparseIntArray;
Brett Chabot1ae2aa62019-03-04 14:14:56 -080067
68import androidx.test.filters.SmallTest;
69import androidx.test.runner.AndroidJUnit4;
Chalard Jean26aa91a2018-03-20 19:13:57 +090070
Chenbo Feng436fe582019-02-25 22:55:58 -080071import com.android.server.LocalServices;
72
Chalard Jean26aa91a2018-03-20 19:13:57 +090073import org.junit.Before;
74import org.junit.Test;
75import org.junit.runner.RunWith;
Chenbo Feng436fe582019-02-25 22:55:58 -080076import org.mockito.ArgumentCaptor;
Chalard Jean26aa91a2018-03-20 19:13:57 +090077import org.mockito.Mock;
78import org.mockito.MockitoAnnotations;
junyulai2454b692018-11-01 17:16:31 +080079import org.mockito.invocation.InvocationOnMock;
80
Chenbo Feng436fe582019-02-25 22:55:58 -080081import java.util.ArrayList;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000082import java.util.Arrays;
83import java.util.Collections;
junyulai2454b692018-11-01 17:16:31 +080084import java.util.HashMap;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000085import java.util.HashSet;
86import java.util.Set;
87
Chalard Jean26aa91a2018-03-20 19:13:57 +090088
89@RunWith(AndroidJUnit4.class)
90@SmallTest
91public class PermissionMonitorTest {
junyulai2454b692018-11-01 17:16:31 +080092 private static final int MOCK_USER1 = 0;
93 private static final int MOCK_USER2 = 1;
94 private static final int MOCK_UID1 = 10001;
Chenbo Feng436fe582019-02-25 22:55:58 -080095 private static final int MOCK_UID2 = 10086;
96 private static final int SYSTEM_UID1 = 1000;
97 private static final int SYSTEM_UID2 = 1008;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000098 private static final int VPN_UID = 10002;
junyulai2454b692018-11-01 17:16:31 +080099 private static final String MOCK_PACKAGE1 = "appName1";
Chenbo Feng436fe582019-02-25 22:55:58 -0800100 private static final String MOCK_PACKAGE2 = "appName2";
junyulai2454b692018-11-01 17:16:31 +0800101 private static final String SYSTEM_PACKAGE1 = "sysName1";
102 private static final String SYSTEM_PACKAGE2 = "sysName2";
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000103 private static final String VPN_PACKAGE = "vpnApp";
paulhub6733802018-08-20 11:01:21 +0800104 private static final String PARTITION_SYSTEM = "system";
105 private static final String PARTITION_OEM = "oem";
106 private static final String PARTITION_PRODUCT = "product";
107 private static final String PARTITION_VENDOR = "vendor";
paulhu3b0f5ea2018-11-01 10:38:11 +0800108 private static final int VERSION_P = Build.VERSION_CODES.P;
109 private static final int VERSION_Q = Build.VERSION_CODES.Q;
Chalard Jean26aa91a2018-03-20 19:13:57 +0900110
111 @Mock private Context mContext;
112 @Mock private PackageManager mPackageManager;
Chenbo Feng436fe582019-02-25 22:55:58 -0800113 @Mock private INetd mNetdService;
114 @Mock private PackageManagerInternal mMockPmi;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000115 @Mock private UserManager mUserManager;
Chalard Jean26aa91a2018-03-20 19:13:57 +0900116
Chenbo Feng436fe582019-02-25 22:55:58 -0800117 private PackageManagerInternal.PackageListObserver mObserver;
Chalard Jean26aa91a2018-03-20 19:13:57 +0900118 private PermissionMonitor mPermissionMonitor;
119
120 @Before
121 public void setUp() throws Exception {
122 MockitoAnnotations.initMocks(this);
123 when(mContext.getPackageManager()).thenReturn(mPackageManager);
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000124 when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
125 when(mUserManager.getUsers(eq(true))).thenReturn(
126 Arrays.asList(new UserInfo[] {
127 new UserInfo(MOCK_USER1, "", 0),
128 new UserInfo(MOCK_USER2, "", 0),
129 }));
130
131 mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService));
Chenbo Feng436fe582019-02-25 22:55:58 -0800132
133 LocalServices.removeServiceForTest(PackageManagerInternal.class);
134 LocalServices.addService(PackageManagerInternal.class, mMockPmi);
135 when(mMockPmi.getPackageList(any())).thenReturn(new PackageList(new ArrayList<String>(),
136 /* observer */ null));
137 when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
138 mPermissionMonitor.startMonitoring();
139
140 final ArgumentCaptor<PackageManagerInternal.PackageListObserver> observerCaptor =
141 ArgumentCaptor.forClass(PackageManagerInternal.PackageListObserver.class);
142 verify(mMockPmi).getPackageList(observerCaptor.capture());
143 mObserver = observerCaptor.getValue();
Chalard Jean26aa91a2018-03-20 19:13:57 +0900144 }
145
paulhu3b0f5ea2018-11-01 10:38:11 +0800146 private boolean hasBgPermission(String partition, int targetSdkVersion, int uid,
147 String... permission) throws Exception {
148 final PackageInfo packageInfo = packageInfoWithPermissions(permission, partition);
paulhub6733802018-08-20 11:01:21 +0800149 packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
paulhu3b0f5ea2018-11-01 10:38:11 +0800150 packageInfo.applicationInfo.uid = uid;
Chalard Jean577164b2018-04-02 16:16:46 +0900151 when(mPackageManager.getPackageInfoAsUser(
junyulai2454b692018-11-01 17:16:31 +0800152 eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
153 when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[] {MOCK_PACKAGE1});
paulhu3b0f5ea2018-11-01 10:38:11 +0800154 return mPermissionMonitor.hasUseBackgroundNetworksPermission(uid);
Chalard Jean26aa91a2018-03-20 19:13:57 +0900155 }
156
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000157 private static PackageInfo packageInfoWithPermissions(String[] permissions, String partition) {
Chenbo Feng436fe582019-02-25 22:55:58 -0800158 int[] requestedPermissionsFlags = new int[permissions.length];
159 for (int i = 0; i < permissions.length; i++) {
160 requestedPermissionsFlags[i] = REQUESTED_PERMISSION_GRANTED;
161 }
162 return packageInfoWithPermissions(permissions, partition,
163 requestedPermissionsFlags);
164 }
165
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000166 private static PackageInfo packageInfoWithPermissions(String[] permissions, String partition,
Chenbo Feng436fe582019-02-25 22:55:58 -0800167 int[] requestedPermissionsFlags) {
Chalard Jean26aa91a2018-03-20 19:13:57 +0900168 final PackageInfo packageInfo = new PackageInfo();
169 packageInfo.requestedPermissions = permissions;
170 packageInfo.applicationInfo = new ApplicationInfo();
Chenbo Feng436fe582019-02-25 22:55:58 -0800171 packageInfo.requestedPermissionsFlags = requestedPermissionsFlags;
paulhub6733802018-08-20 11:01:21 +0800172 int privateFlags = 0;
173 switch (partition) {
174 case PARTITION_OEM:
175 privateFlags = PRIVATE_FLAG_OEM;
176 break;
177 case PARTITION_PRODUCT:
178 privateFlags = PRIVATE_FLAG_PRODUCT;
179 break;
180 case PARTITION_VENDOR:
181 privateFlags = PRIVATE_FLAG_VENDOR;
182 break;
183 }
184 packageInfo.applicationInfo.privateFlags = privateFlags;
Chalard Jean26aa91a2018-03-20 19:13:57 +0900185 return packageInfo;
186 }
187
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000188 private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid, int userId) {
189 final PackageInfo pkgInfo;
190 if (hasSystemPermission) {
191 pkgInfo = packageInfoWithPermissions(new String[] {CHANGE_NETWORK_STATE, NETWORK_STACK},
192 PARTITION_SYSTEM);
193 } else {
194 pkgInfo = packageInfoWithPermissions(new String[] {}, "");
195 }
196 pkgInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
197 return pkgInfo;
198 }
199
Chalard Jean26aa91a2018-03-20 19:13:57 +0900200 @Test
201 public void testHasPermission() {
paulhub6733802018-08-20 11:01:21 +0800202 PackageInfo app = packageInfoWithPermissions(new String[] {}, PARTITION_SYSTEM);
Chalard Jean26aa91a2018-03-20 19:13:57 +0900203 assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
204 assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
205 assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
206 assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
207
208 app = packageInfoWithPermissions(new String[] {
paulhub6733802018-08-20 11:01:21 +0800209 CHANGE_NETWORK_STATE, NETWORK_STACK
210 }, PARTITION_SYSTEM);
Chalard Jean26aa91a2018-03-20 19:13:57 +0900211 assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
212 assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
213 assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
214 assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
215
216 app = packageInfoWithPermissions(new String[] {
paulhub6733802018-08-20 11:01:21 +0800217 CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL
218 }, PARTITION_SYSTEM);
Chalard Jean26aa91a2018-03-20 19:13:57 +0900219 assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
220 assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
221 assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
222 assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
223 }
224
225 @Test
paulhub6733802018-08-20 11:01:21 +0800226 public void testIsVendorApp() {
227 PackageInfo app = packageInfoWithPermissions(new String[] {}, PARTITION_SYSTEM);
228 assertFalse(mPermissionMonitor.isVendorApp(app.applicationInfo));
229 app = packageInfoWithPermissions(new String[] {}, PARTITION_OEM);
230 assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
231 app = packageInfoWithPermissions(new String[] {}, PARTITION_PRODUCT);
232 assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
233 app = packageInfoWithPermissions(new String[] {}, PARTITION_VENDOR);
234 assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
Chalard Jean26aa91a2018-03-20 19:13:57 +0900235 }
236
237 @Test
238 public void testHasUseBackgroundNetworksPermission() throws Exception {
junyulai2454b692018-11-01 17:16:31 +0800239 assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
240 assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
241 assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, NETWORK_STACK));
242 assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
243 assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1,
paulhu3b0f5ea2018-11-01 10:38:11 +0800244 CONNECTIVITY_USE_RESTRICTED_NETWORKS));
junyulai2454b692018-11-01 17:16:31 +0800245 assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
Chalard Jean26aa91a2018-03-20 19:13:57 +0900246
junyulai2454b692018-11-01 17:16:31 +0800247 assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
248 assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE));
paulhu3b0f5ea2018-11-01 10:38:11 +0800249 }
Chalard Jean26aa91a2018-03-20 19:13:57 +0900250
paulhu3b0f5ea2018-11-01 10:38:11 +0800251 @Test
252 public void testHasUseBackgroundNetworksPermissionSystemUid() throws Exception {
junyulai345155e2018-11-09 12:37:16 +0800253 doReturn(VERSION_P).when(mPermissionMonitor).getDeviceFirstSdkInt();
paulhu3b0f5ea2018-11-01 10:38:11 +0800254 assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
255 assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CHANGE_WIFI_STATE));
256 assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID,
257 CONNECTIVITY_USE_RESTRICTED_NETWORKS));
Chalard Jean26aa91a2018-03-20 19:13:57 +0900258
junyulai345155e2018-11-09 12:37:16 +0800259 doReturn(VERSION_Q).when(mPermissionMonitor).getDeviceFirstSdkInt();
paulhu3b0f5ea2018-11-01 10:38:11 +0800260 assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
261 assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CHANGE_WIFI_STATE));
262 assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID,
263 CONNECTIVITY_USE_RESTRICTED_NETWORKS));
264 }
265
266 @Test
267 public void testHasUseBackgroundNetworksPermissionVendorApp() throws Exception {
junyulai2454b692018-11-01 17:16:31 +0800268 assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
269 assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
270 assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, NETWORK_STACK));
271 assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
272 assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1,
paulhu3b0f5ea2018-11-01 10:38:11 +0800273 CONNECTIVITY_USE_RESTRICTED_NETWORKS));
junyulai2454b692018-11-01 17:16:31 +0800274 assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
paulhu3b0f5ea2018-11-01 10:38:11 +0800275
junyulai2454b692018-11-01 17:16:31 +0800276 assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
277 assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE));
278 }
279
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000280 private class NetdMonitor {
junyulai2454b692018-11-01 17:16:31 +0800281 private final HashMap<Integer, Boolean> mApps = new HashMap<>();
282
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000283 NetdMonitor(INetd mockNetd) throws Exception {
junyulai2454b692018-11-01 17:16:31 +0800284 // Add hook to verify and track result of setPermission.
285 doAnswer((InvocationOnMock invocation) -> {
286 final Object[] args = invocation.getArguments();
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000287 final Boolean isSystem = args[0].equals(INetd.PERMISSION_SYSTEM);
junyulai2454b692018-11-01 17:16:31 +0800288 for (final int uid : (int[]) args[1]) {
289 // TODO: Currently, permission monitor will send duplicate commands for each uid
290 // corresponding to each user. Need to fix that and uncomment below test.
291 // if (mApps.containsKey(uid) && mApps.get(uid) == isSystem) {
292 // fail("uid " + uid + " is already set to " + isSystem);
293 // }
294 mApps.put(uid, isSystem);
295 }
296 return null;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000297 }).when(mockNetd).networkSetPermissionForUser(anyInt(), any(int[].class));
junyulai2454b692018-11-01 17:16:31 +0800298
299 // Add hook to verify and track result of clearPermission.
300 doAnswer((InvocationOnMock invocation) -> {
301 final Object[] args = invocation.getArguments();
302 for (final int uid : (int[]) args[0]) {
303 // TODO: Currently, permission monitor will send duplicate commands for each uid
304 // corresponding to each user. Need to fix that and uncomment below test.
305 // if (!mApps.containsKey(uid)) {
306 // fail("uid " + uid + " does not exist.");
307 // }
308 mApps.remove(uid);
309 }
310 return null;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000311 }).when(mockNetd).networkClearPermissionForUser(any(int[].class));
junyulai2454b692018-11-01 17:16:31 +0800312 }
313
314 public void expectPermission(Boolean permission, int[] users, int[] apps) {
315 for (final int user : users) {
316 for (final int app : apps) {
317 final int uid = UserHandle.getUid(user, app);
318 if (!mApps.containsKey(uid)) {
319 fail("uid " + uid + " does not exist.");
320 }
321 if (mApps.get(uid) != permission) {
322 fail("uid " + uid + " has wrong permission: " + permission);
323 }
324 }
325 }
326 }
327
328 public void expectNoPermission(int[] users, int[] apps) {
329 for (final int user : users) {
330 for (final int app : apps) {
331 final int uid = UserHandle.getUid(user, app);
332 if (mApps.containsKey(uid)) {
333 fail("uid " + uid + " has listed permissions, expected none.");
334 }
335 }
336 }
337 }
338 }
339
340 @Test
341 public void testUserAndPackageAddRemove() throws Exception {
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000342 final NetdMonitor mNetdMonitor = new NetdMonitor(mNetdService);
junyulai2454b692018-11-01 17:16:31 +0800343
344 // MOCK_UID1: MOCK_PACKAGE1 only has network permission.
345 // SYSTEM_UID: SYSTEM_PACKAGE1 has system permission.
346 // SYSTEM_UID: SYSTEM_PACKAGE2 only has network permission.
347 doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(eq(SYSTEM), anyString());
348 doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(any(),
349 eq(SYSTEM_PACKAGE1));
350 doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
351 eq(SYSTEM_PACKAGE2));
352 doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
353 eq(MOCK_PACKAGE1));
354
355 // Add SYSTEM_PACKAGE2, expect only have network permission.
356 mPermissionMonitor.onUserAdded(MOCK_USER1);
357 addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_UID);
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000358 mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID});
junyulai2454b692018-11-01 17:16:31 +0800359
360 // Add SYSTEM_PACKAGE1, expect permission escalate.
361 addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_UID);
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000362 mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID});
junyulai2454b692018-11-01 17:16:31 +0800363
364 mPermissionMonitor.onUserAdded(MOCK_USER2);
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000365 mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2},
junyulai2454b692018-11-01 17:16:31 +0800366 new int[]{SYSTEM_UID});
367
368 addPackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000369 mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2},
junyulai2454b692018-11-01 17:16:31 +0800370 new int[]{SYSTEM_UID});
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000371 mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
junyulai2454b692018-11-01 17:16:31 +0800372 new int[]{MOCK_UID1});
373
374 // Remove MOCK_UID1, expect no permission left for all user.
375 mPermissionMonitor.onPackageRemoved(MOCK_UID1);
376 removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_UID1);
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000377 mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{MOCK_UID1});
junyulai2454b692018-11-01 17:16:31 +0800378
379 // Remove SYSTEM_PACKAGE1, expect permission downgrade.
380 when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{SYSTEM_PACKAGE2});
381 removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, SYSTEM_UID);
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000382 mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
junyulai2454b692018-11-01 17:16:31 +0800383 new int[]{SYSTEM_UID});
384
385 mPermissionMonitor.onUserRemoved(MOCK_USER1);
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000386 mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER2}, new int[]{SYSTEM_UID});
junyulai2454b692018-11-01 17:16:31 +0800387
388 // Remove all packages, expect no permission left.
389 when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{});
390 removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_UID);
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000391 mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
junyulai2454b692018-11-01 17:16:31 +0800392 new int[]{SYSTEM_UID, MOCK_UID1});
393
394 // Remove last user, expect no redundant clearPermission is invoked.
395 mPermissionMonitor.onUserRemoved(MOCK_USER2);
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000396 mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
junyulai2454b692018-11-01 17:16:31 +0800397 new int[]{SYSTEM_UID, MOCK_UID1});
398 }
399
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000400 @Test
401 public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdates() throws Exception {
402 when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
403 Arrays.asList(new PackageInfo[] {
404 buildPackageInfo(/* SYSTEM */ true, SYSTEM_UID1, MOCK_USER1),
405 buildPackageInfo(/* SYSTEM */ false, MOCK_UID1, MOCK_USER1),
406 buildPackageInfo(/* SYSTEM */ false, MOCK_UID2, MOCK_USER1),
407 buildPackageInfo(/* SYSTEM */ false, VPN_UID, MOCK_USER1)
408 }));
409 when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
410 buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
411 mPermissionMonitor.startMonitoring();
412 // Every app on user 0 except MOCK_UID2 are under VPN.
413 final Set<UidRange> vpnRange1 = new HashSet<>(Arrays.asList(new UidRange[] {
414 new UidRange(0, MOCK_UID2 - 1),
415 new UidRange(MOCK_UID2 + 1, UserHandle.PER_USER_RANGE - 1)}));
416 final Set<UidRange> vpnRange2 = Collections.singleton(new UidRange(MOCK_UID2, MOCK_UID2));
417
418 // When VPN is connected, expect a rule to be set up for user app MOCK_UID1
419 mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange1, VPN_UID);
420 verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
421 aryEq(new int[] {MOCK_UID1}));
422
423 reset(mNetdService);
424
425 // When MOCK_UID1 package is uninstalled and reinstalled, expect Netd to be updated
426 mPermissionMonitor.onPackageRemoved(UserHandle.getUid(MOCK_USER1, MOCK_UID1));
427 verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
428 mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1));
429 verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
430 aryEq(new int[] {MOCK_UID1}));
431
432 reset(mNetdService);
433
434 // During VPN uid update (vpnRange1 -> vpnRange2), ConnectivityService first deletes the
435 // old UID rules then adds the new ones. Expect netd to be updated
436 mPermissionMonitor.onVpnUidRangesRemoved("tun0", vpnRange1, VPN_UID);
437 verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
438 mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange2, VPN_UID);
439 verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
440 aryEq(new int[] {MOCK_UID2}));
441
442 reset(mNetdService);
443
444 // When VPN is disconnected, expect rules to be torn down
445 mPermissionMonitor.onVpnUidRangesRemoved("tun0", vpnRange2, VPN_UID);
446 verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID2}));
447 assertNull(mPermissionMonitor.getVpnUidRanges("tun0"));
448 }
449
450 @Test
451 public void testUidFilteringDuringPackageInstallAndUninstall() throws Exception {
452 when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
453 Arrays.asList(new PackageInfo[] {
454 buildPackageInfo(true, SYSTEM_UID1, MOCK_USER1),
455 buildPackageInfo(false, VPN_UID, MOCK_USER1)
456 }));
457 when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
458 buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
459
460 mPermissionMonitor.startMonitoring();
461 final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(MOCK_USER1));
462 mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange, VPN_UID);
463
464 // Newly-installed package should have uid rules added
465 mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1));
466 verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
467 aryEq(new int[] {MOCK_UID1}));
468
469 // Removed package should have its uid rules removed
470 mPermissionMonitor.onPackageRemoved(UserHandle.getUid(MOCK_USER1, MOCK_UID1));
471 verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
472 }
473
474
junyulai2454b692018-11-01 17:16:31 +0800475 // Normal package add/remove operations will trigger multiple intent for uids corresponding to
476 // each user. To simulate generic package operations, the onPackageAdded/Removed will need to be
477 // called multiple times with the uid corresponding to each user.
478 private void addPackageForUsers(int[] users, String packageName, int uid) {
479 for (final int user : users) {
480 mPermissionMonitor.onPackageAdded(packageName, UserHandle.getUid(user, uid));
481 }
482 }
483
484 private void removePackageForUsers(int[] users, int uid) {
485 for (final int user : users) {
486 mPermissionMonitor.onPackageRemoved(UserHandle.getUid(user, uid));
487 }
Chalard Jean26aa91a2018-03-20 19:13:57 +0900488 }
Chenbo Feng436fe582019-02-25 22:55:58 -0800489
490 private class NetdServiceMonitor {
491 private final HashMap<Integer, Integer> mPermissions = new HashMap<>();
492
493 NetdServiceMonitor(INetd mockNetdService) throws Exception {
494 // Add hook to verify and track result of setPermission.
495 doAnswer((InvocationOnMock invocation) -> {
496 final Object[] args = invocation.getArguments();
497 final int permission = (int) args[0];
498 for (final int uid : (int[]) args[1]) {
499 mPermissions.put(uid, permission);
500 }
501 return null;
502 }).when(mockNetdService).trafficSetNetPermForUids(anyInt(), any(int[].class));
503 }
504
505 public void expectPermission(int permission, int[] apps) {
506 for (final int app : apps) {
507 if (!mPermissions.containsKey(app)) {
508 fail("uid " + app + " does not exist.");
509 }
510 if (mPermissions.get(app) != permission) {
511 fail("uid " + app + " has wrong permission: " + mPermissions.get(app));
512 }
513 }
514 }
515 }
516
517 @Test
518 public void testPackagePermissionUpdate() throws Exception {
519 final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
520 // MOCK_UID1: MOCK_PACKAGE1 only has internet permission.
521 // MOCK_UID2: MOCK_PACKAGE2 does not have any permission.
522 // SYSTEM_UID1: SYSTEM_PACKAGE1 has internet permission and update device stats permission.
523 // SYSTEM_UID2: SYSTEM_PACKAGE2 has only update device stats permission.
524
525 SparseIntArray netdPermissionsAppIds = new SparseIntArray();
526 netdPermissionsAppIds.put(MOCK_UID1, INetd.PERMISSION_INTERNET);
527 netdPermissionsAppIds.put(MOCK_UID2, INetd.NO_PERMISSIONS);
528 netdPermissionsAppIds.put(SYSTEM_UID1, INetd.PERMISSION_INTERNET
529 | INetd.PERMISSION_UPDATE_DEVICE_STATS);
530 netdPermissionsAppIds.put(SYSTEM_UID2, INetd.PERMISSION_UPDATE_DEVICE_STATS);
531
532 // Send the permission information to netd, expect permission updated.
533 mPermissionMonitor.sendPackagePermissionsToNetd(netdPermissionsAppIds);
534
535 mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET,
536 new int[]{MOCK_UID1});
537 mNetdServiceMonitor.expectPermission(INetd.NO_PERMISSIONS, new int[]{MOCK_UID2});
538 mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
539 | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1});
540 mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UPDATE_DEVICE_STATS,
541 new int[]{SYSTEM_UID2});
542
543 // Update permission of MOCK_UID1, expect new permission show up.
544 mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1,
545 INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS);
546 mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
547 | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
548
549 // Change permissions of SYSTEM_UID2, expect new permission show up and old permission
550 // revoked.
551 mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2,
552 INetd.PERMISSION_INTERNET);
553 mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{SYSTEM_UID2});
554
555 // Revoke permission from SYSTEM_UID1, expect no permission stored.
556 mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, INetd.NO_PERMISSIONS);
557 mNetdServiceMonitor.expectPermission(INetd.NO_PERMISSIONS, new int[]{SYSTEM_UID1});
558 }
559
560 private PackageInfo addPackage(String packageName, int uid, String[] permissions)
561 throws Exception {
562 PackageInfo packageInfo = packageInfoWithPermissions(permissions, PARTITION_SYSTEM);
563 when(mPackageManager.getPackageInfo(eq(packageName), anyInt())).thenReturn(packageInfo);
564 when(mPackageManager.getPackagesForUid(eq(uid))).thenReturn(new String[]{packageName});
565 mObserver.onPackageAdded(packageName, uid);
566 return packageInfo;
567 }
568
569 @Test
570 public void testPackageInstall() throws Exception {
571 final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
572
573 addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
574 mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
575 | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
576
577 addPackage(MOCK_PACKAGE2, MOCK_UID2, new String[] {INTERNET});
578 mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID2});
579 }
580
581 @Test
582 public void testPackageInstallSharedUid() throws Exception {
583 final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
584
585 PackageInfo packageInfo1 = addPackage(MOCK_PACKAGE1, MOCK_UID1,
586 new String[] {INTERNET, UPDATE_DEVICE_STATS});
587 mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
588 | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
589
590 // Install another package with the same uid and no permissions should not cause the UID to
591 // lose permissions.
592 PackageInfo packageInfo2 = packageInfoWithPermissions(new String[]{}, PARTITION_SYSTEM);
593 when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
594 when(mPackageManager.getPackagesForUid(MOCK_UID1))
595 .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
596 mObserver.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1);
597 mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
598 | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
599 }
600
601 @Test
602 public void testPackageUninstallBasic() throws Exception {
603 final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
604
605 addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
606 mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
607 | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
608
609 when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
610 mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
Chenbo Fenga6817cd2019-03-25 18:13:34 -0700611 mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
Chenbo Feng436fe582019-02-25 22:55:58 -0800612 }
613
614 @Test
615 public void testPackageUpdate() throws Exception {
616 final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
617
618 addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
619 mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
620 | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
621
622 // Remove and install the same package to simulate the update action
623 when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
624 mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
Chenbo Fenga6817cd2019-03-25 18:13:34 -0700625 mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
Chenbo Feng436fe582019-02-25 22:55:58 -0800626
627 addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
628 mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
629 }
630
631 @Test
632 public void testPackageUninstallWithMultiplePackages() throws Exception {
633 final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
634
635 addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
636 mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
637 | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
638
639 // Mock another package with the same uid but different permissions.
640 PackageInfo packageInfo2 = packageInfoWithPermissions(new String[] {INTERNET},
641 PARTITION_SYSTEM);
642 when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
643 when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{
644 MOCK_PACKAGE2});
645
646 mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
647 mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
648 }
Chalard Jean26aa91a2018-03-20 19:13:57 +0900649}