1 /* 2 * Copyright (C) 2014 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 com.android.server.connectivity; 18 19 import static android.Manifest.permission.CHANGE_NETWORK_STATE; 20 import static android.Manifest.permission.CONNECTIVITY_INTERNAL; 21 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; 22 import static android.Manifest.permission.INTERNET; 23 import static android.Manifest.permission.NETWORK_STACK; 24 import static android.Manifest.permission.UPDATE_DEVICE_STATS; 25 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; 26 import static android.content.pm.PackageManager.GET_PERMISSIONS; 27 import static android.content.pm.PackageManager.MATCH_ANY_USER; 28 import static android.os.Process.INVALID_UID; 29 import static android.os.Process.SYSTEM_UID; 30 31 import android.annotation.NonNull; 32 import android.content.Context; 33 import android.content.pm.ApplicationInfo; 34 import android.content.pm.PackageInfo; 35 import android.content.pm.PackageManager; 36 import android.content.pm.PackageManager.NameNotFoundException; 37 import android.content.pm.PackageManagerInternal; 38 import android.content.pm.UserInfo; 39 import android.net.INetd; 40 import android.net.UidRange; 41 import android.os.Build; 42 import android.os.RemoteException; 43 import android.os.ServiceSpecificException; 44 import android.os.UserHandle; 45 import android.os.UserManager; 46 import android.system.OsConstants; 47 import android.util.ArraySet; 48 import android.util.Log; 49 import android.util.SparseArray; 50 import android.util.SparseIntArray; 51 52 import com.android.internal.annotations.GuardedBy; 53 import com.android.internal.annotations.VisibleForTesting; 54 import com.android.internal.util.ArrayUtils; 55 import com.android.internal.util.IndentingPrintWriter; 56 import com.android.server.LocalServices; 57 import com.android.server.SystemConfig; 58 59 import java.util.ArrayList; 60 import java.util.Collection; 61 import java.util.HashMap; 62 import java.util.HashSet; 63 import java.util.List; 64 import java.util.Map; 65 import java.util.Map.Entry; 66 import java.util.Set; 67 68 69 /** 70 * A utility class to inform Netd of UID permisisons. 71 * Does a mass update at boot and then monitors for app install/remove. 72 * 73 * @hide 74 */ 75 public class PermissionMonitor { 76 private static final String TAG = "PermissionMonitor"; 77 private static final boolean DBG = true; 78 protected static final Boolean SYSTEM = Boolean.TRUE; 79 protected static final Boolean NETWORK = Boolean.FALSE; 80 private static final int VERSION_Q = Build.VERSION_CODES.Q; 81 82 private final PackageManager mPackageManager; 83 private final UserManager mUserManager; 84 private final INetd mNetd; 85 86 // Values are User IDs. 87 @GuardedBy("this") 88 private final Set<Integer> mUsers = new HashSet<>(); 89 90 // Keys are app uids. Values are true for SYSTEM permission and false for NETWORK permission. 91 @GuardedBy("this") 92 private final Map<Integer, Boolean> mApps = new HashMap<>(); 93 94 // Keys are active non-bypassable and fully-routed VPN's interface name, Values are uid ranges 95 // for apps under the VPN 96 @GuardedBy("this") 97 private final Map<String, Set<UidRange>> mVpnUidRanges = new HashMap<>(); 98 99 // A set of appIds for apps across all users on the device. We track appIds instead of uids 100 // directly to reduce its size and also eliminate the need to update this set when user is 101 // added/removed. 102 @GuardedBy("this") 103 private final Set<Integer> mAllApps = new HashSet<>(); 104 105 private class PackageListObserver implements PackageManagerInternal.PackageListObserver { 106 getPermissionForUid(int uid)107 private int getPermissionForUid(int uid) { 108 int permission = 0; 109 // Check all the packages for this UID. The UID has the permission if any of the 110 // packages in it has the permission. 111 String[] packages = mPackageManager.getPackagesForUid(uid); 112 if (packages != null && packages.length > 0) { 113 for (String name : packages) { 114 final PackageInfo app = getPackageInfo(name); 115 if (app != null && app.requestedPermissions != null) { 116 permission |= getNetdPermissionMask(app.requestedPermissions, 117 app.requestedPermissionsFlags); 118 } 119 } 120 } else { 121 // The last package of this uid is removed from device. Clean the package up. 122 permission = INetd.PERMISSION_UNINSTALLED; 123 } 124 return permission; 125 } 126 127 @Override onPackageAdded(String packageName, int uid)128 public void onPackageAdded(String packageName, int uid) { 129 sendPackagePermissionsForUid(uid, getPermissionForUid(uid)); 130 } 131 132 @Override onPackageRemoved(String packageName, int uid)133 public void onPackageRemoved(String packageName, int uid) { 134 sendPackagePermissionsForUid(uid, getPermissionForUid(uid)); 135 } 136 } 137 PermissionMonitor(Context context, INetd netd)138 public PermissionMonitor(Context context, INetd netd) { 139 mPackageManager = context.getPackageManager(); 140 mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 141 mNetd = netd; 142 } 143 144 // Intended to be called only once at startup, after the system is ready. Installs a broadcast 145 // receiver to monitor ongoing UID changes, so this shouldn't/needn't be called again. startMonitoring()146 public synchronized void startMonitoring() { 147 log("Monitoring"); 148 149 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); 150 if (pmi != null) { 151 pmi.getPackageList(new PackageListObserver()); 152 } else { 153 loge("failed to get the PackageManagerInternal service"); 154 } 155 List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS 156 | MATCH_ANY_USER); 157 if (apps == null) { 158 loge("No apps"); 159 return; 160 } 161 162 SparseIntArray netdPermsUids = new SparseIntArray(); 163 164 for (PackageInfo app : apps) { 165 int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID; 166 if (uid < 0) { 167 continue; 168 } 169 mAllApps.add(UserHandle.getAppId(uid)); 170 171 boolean isNetwork = hasNetworkPermission(app); 172 boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app); 173 174 if (isNetwork || hasRestrictedPermission) { 175 Boolean permission = mApps.get(uid); 176 // If multiple packages share a UID (cf: android:sharedUserId) and ask for different 177 // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is). 178 if (permission == null || permission == NETWORK) { 179 mApps.put(uid, hasRestrictedPermission); 180 } 181 } 182 183 //TODO: unify the management of the permissions into one codepath. 184 int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions, 185 app.requestedPermissionsFlags); 186 netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms); 187 } 188 189 List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users 190 if (users != null) { 191 for (UserInfo user : users) { 192 mUsers.add(user.id); 193 } 194 } 195 196 final SparseArray<ArraySet<String>> systemPermission = 197 SystemConfig.getInstance().getSystemPermissions(); 198 for (int i = 0; i < systemPermission.size(); i++) { 199 ArraySet<String> perms = systemPermission.valueAt(i); 200 int uid = systemPermission.keyAt(i); 201 int netdPermission = 0; 202 // Get the uids of native services that have UPDATE_DEVICE_STATS or INTERNET permission. 203 if (perms != null) { 204 netdPermission |= perms.contains(UPDATE_DEVICE_STATS) 205 ? INetd.PERMISSION_UPDATE_DEVICE_STATS : 0; 206 netdPermission |= perms.contains(INTERNET) 207 ? INetd.PERMISSION_INTERNET : 0; 208 } 209 netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission); 210 } 211 log("Users: " + mUsers.size() + ", Apps: " + mApps.size()); 212 update(mUsers, mApps, true); 213 sendPackagePermissionsToNetd(netdPermsUids); 214 } 215 216 @VisibleForTesting isVendorApp(@onNull ApplicationInfo appInfo)217 static boolean isVendorApp(@NonNull ApplicationInfo appInfo) { 218 return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct(); 219 } 220 221 @VisibleForTesting getDeviceFirstSdkInt()222 protected int getDeviceFirstSdkInt() { 223 return Build.VERSION.FIRST_SDK_INT; 224 } 225 226 @VisibleForTesting hasPermission(PackageInfo app, String permission)227 boolean hasPermission(PackageInfo app, String permission) { 228 if (app.requestedPermissions != null) { 229 for (String p : app.requestedPermissions) { 230 if (permission.equals(p)) { 231 return true; 232 } 233 } 234 } 235 return false; 236 } 237 hasNetworkPermission(PackageInfo app)238 private boolean hasNetworkPermission(PackageInfo app) { 239 return hasPermission(app, CHANGE_NETWORK_STATE); 240 } 241 hasRestrictedNetworkPermission(PackageInfo app)242 private boolean hasRestrictedNetworkPermission(PackageInfo app) { 243 // TODO : remove this check in the future(b/31479477). All apps should just 244 // request the appropriate permission for their use case since android Q. 245 if (app.applicationInfo != null) { 246 // Backward compatibility for b/114245686, on devices that launched before Q daemons 247 // and apps running as the system UID are exempted from this check. 248 if (app.applicationInfo.uid == SYSTEM_UID && getDeviceFirstSdkInt() < VERSION_Q) { 249 return true; 250 } 251 252 if (app.applicationInfo.targetSdkVersion < VERSION_Q 253 && isVendorApp(app.applicationInfo)) { 254 return true; 255 } 256 } 257 return hasPermission(app, CONNECTIVITY_INTERNAL) 258 || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS); 259 } 260 hasUseBackgroundNetworksPermission(PackageInfo app)261 private boolean hasUseBackgroundNetworksPermission(PackageInfo app) { 262 // This function defines what it means to hold the permission to use 263 // background networks. 264 return hasPermission(app, CHANGE_NETWORK_STATE) 265 || hasPermission(app, NETWORK_STACK) 266 || hasRestrictedNetworkPermission(app); 267 } 268 hasUseBackgroundNetworksPermission(int uid)269 public boolean hasUseBackgroundNetworksPermission(int uid) { 270 final String[] names = mPackageManager.getPackagesForUid(uid); 271 if (null == names || names.length == 0) return false; 272 try { 273 // Only using the first package name. There may be multiple names if multiple 274 // apps share the same UID, but in that case they also share permissions so 275 // querying with any of the names will return the same results. 276 int userId = UserHandle.getUserId(uid); 277 final PackageInfo app = mPackageManager.getPackageInfoAsUser( 278 names[0], GET_PERMISSIONS, userId); 279 return hasUseBackgroundNetworksPermission(app); 280 } catch (NameNotFoundException e) { 281 // App not found. 282 loge("NameNotFoundException " + names[0], e); 283 return false; 284 } 285 } 286 toIntArray(Collection<Integer> list)287 private int[] toIntArray(Collection<Integer> list) { 288 int[] array = new int[list.size()]; 289 int i = 0; 290 for (Integer item : list) { 291 array[i++] = item; 292 } 293 return array; 294 } 295 update(Set<Integer> users, Map<Integer, Boolean> apps, boolean add)296 private void update(Set<Integer> users, Map<Integer, Boolean> apps, boolean add) { 297 List<Integer> network = new ArrayList<>(); 298 List<Integer> system = new ArrayList<>(); 299 for (Entry<Integer, Boolean> app : apps.entrySet()) { 300 List<Integer> list = app.getValue() ? system : network; 301 for (int user : users) { 302 list.add(UserHandle.getUid(user, app.getKey())); 303 } 304 } 305 try { 306 if (add) { 307 mNetd.networkSetPermissionForUser(INetd.PERMISSION_NETWORK, toIntArray(network)); 308 mNetd.networkSetPermissionForUser(INetd.PERMISSION_SYSTEM, toIntArray(system)); 309 } else { 310 mNetd.networkClearPermissionForUser(toIntArray(network)); 311 mNetd.networkClearPermissionForUser(toIntArray(system)); 312 } 313 } catch (RemoteException e) { 314 loge("Exception when updating permissions: " + e); 315 } 316 } 317 318 /** 319 * Called when a user is added. See {link #ACTION_USER_ADDED}. 320 * 321 * @param user The integer userHandle of the added user. See {@link #EXTRA_USER_HANDLE}. 322 * 323 * @hide 324 */ onUserAdded(int user)325 public synchronized void onUserAdded(int user) { 326 if (user < 0) { 327 loge("Invalid user in onUserAdded: " + user); 328 return; 329 } 330 mUsers.add(user); 331 332 Set<Integer> users = new HashSet<>(); 333 users.add(user); 334 update(users, mApps, true); 335 } 336 337 /** 338 * Called when an user is removed. See {link #ACTION_USER_REMOVED}. 339 * 340 * @param user The integer userHandle of the removed user. See {@link #EXTRA_USER_HANDLE}. 341 * 342 * @hide 343 */ onUserRemoved(int user)344 public synchronized void onUserRemoved(int user) { 345 if (user < 0) { 346 loge("Invalid user in onUserRemoved: " + user); 347 return; 348 } 349 mUsers.remove(user); 350 351 Set<Integer> users = new HashSet<>(); 352 users.add(user); 353 update(users, mApps, false); 354 } 355 356 @VisibleForTesting highestPermissionForUid(Boolean currentPermission, String name)357 protected Boolean highestPermissionForUid(Boolean currentPermission, String name) { 358 if (currentPermission == SYSTEM) { 359 return currentPermission; 360 } 361 try { 362 final PackageInfo app = mPackageManager.getPackageInfo(name, GET_PERMISSIONS); 363 final boolean isNetwork = hasNetworkPermission(app); 364 final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app); 365 if (isNetwork || hasRestrictedPermission) { 366 currentPermission = hasRestrictedPermission; 367 } 368 } catch (NameNotFoundException e) { 369 // App not found. 370 loge("NameNotFoundException " + name); 371 } 372 return currentPermission; 373 } 374 375 /** 376 * Called when a package is added. See {link #ACTION_PACKAGE_ADDED}. 377 * 378 * @param packageName The name of the new package. 379 * @param uid The uid of the new package. 380 * 381 * @hide 382 */ onPackageAdded(String packageName, int uid)383 public synchronized void onPackageAdded(String packageName, int uid) { 384 // If multiple packages share a UID (cf: android:sharedUserId) and ask for different 385 // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is). 386 final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName); 387 if (permission != mApps.get(uid)) { 388 mApps.put(uid, permission); 389 390 Map<Integer, Boolean> apps = new HashMap<>(); 391 apps.put(uid, permission); 392 update(mUsers, apps, true); 393 } 394 395 // If the newly-installed package falls within some VPN's uid range, update Netd with it. 396 // This needs to happen after the mApps update above, since removeBypassingUids() depends 397 // on mApps to check if the package can bypass VPN. 398 for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) { 399 if (UidRange.containsUid(vpn.getValue(), uid)) { 400 final Set<Integer> changedUids = new HashSet<>(); 401 changedUids.add(uid); 402 removeBypassingUids(changedUids, /* vpnAppUid */ -1); 403 updateVpnUids(vpn.getKey(), changedUids, true); 404 } 405 } 406 mAllApps.add(UserHandle.getAppId(uid)); 407 } 408 409 /** 410 * Called when a package is removed. See {link #ACTION_PACKAGE_REMOVED}. 411 * 412 * @param uid containing the integer uid previously assigned to the package. 413 * 414 * @hide 415 */ onPackageRemoved(int uid)416 public synchronized void onPackageRemoved(int uid) { 417 // If the newly-removed package falls within some VPN's uid range, update Netd with it. 418 // This needs to happen before the mApps update below, since removeBypassingUids() depends 419 // on mApps to check if the package can bypass VPN. 420 for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) { 421 if (UidRange.containsUid(vpn.getValue(), uid)) { 422 final Set<Integer> changedUids = new HashSet<>(); 423 changedUids.add(uid); 424 removeBypassingUids(changedUids, /* vpnAppUid */ -1); 425 updateVpnUids(vpn.getKey(), changedUids, false); 426 } 427 } 428 // If the package has been removed from all users on the device, clear it form mAllApps. 429 if (mPackageManager.getNameForUid(uid) == null) { 430 mAllApps.remove(UserHandle.getAppId(uid)); 431 } 432 433 Map<Integer, Boolean> apps = new HashMap<>(); 434 Boolean permission = null; 435 String[] packages = mPackageManager.getPackagesForUid(uid); 436 if (packages != null && packages.length > 0) { 437 for (String name : packages) { 438 permission = highestPermissionForUid(permission, name); 439 if (permission == SYSTEM) { 440 // An app with this UID still has the SYSTEM permission. 441 // Therefore, this UID must already have the SYSTEM permission. 442 // Nothing to do. 443 return; 444 } 445 } 446 } 447 if (permission == mApps.get(uid)) { 448 // The permissions of this UID have not changed. Nothing to do. 449 return; 450 } else if (permission != null) { 451 mApps.put(uid, permission); 452 apps.put(uid, permission); 453 update(mUsers, apps, true); 454 } else { 455 mApps.remove(uid); 456 apps.put(uid, NETWORK); // doesn't matter which permission we pick here 457 update(mUsers, apps, false); 458 } 459 } 460 getNetdPermissionMask(String[] requestedPermissions, int[] requestedPermissionsFlags)461 private static int getNetdPermissionMask(String[] requestedPermissions, 462 int[] requestedPermissionsFlags) { 463 int permissions = 0; 464 if (requestedPermissions == null || requestedPermissionsFlags == null) return permissions; 465 for (int i = 0; i < requestedPermissions.length; i++) { 466 if (requestedPermissions[i].equals(INTERNET) 467 && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) { 468 permissions |= INetd.PERMISSION_INTERNET; 469 } 470 if (requestedPermissions[i].equals(UPDATE_DEVICE_STATS) 471 && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) { 472 permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS; 473 } 474 } 475 return permissions; 476 } 477 getPackageInfo(String packageName)478 private PackageInfo getPackageInfo(String packageName) { 479 try { 480 PackageInfo app = mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS 481 | MATCH_ANY_USER); 482 return app; 483 } catch (NameNotFoundException e) { 484 return null; 485 } 486 } 487 488 /** 489 * Called when a new set of UID ranges are added to an active VPN network 490 * 491 * @param iface The active VPN network's interface name 492 * @param rangesToAdd The new UID ranges to be added to the network 493 * @param vpnAppUid The uid of the VPN app 494 */ onVpnUidRangesAdded(@onNull String iface, Set<UidRange> rangesToAdd, int vpnAppUid)495 public synchronized void onVpnUidRangesAdded(@NonNull String iface, Set<UidRange> rangesToAdd, 496 int vpnAppUid) { 497 // Calculate the list of new app uids under the VPN due to the new UID ranges and update 498 // Netd about them. Because mAllApps only contains appIds instead of uids, the result might 499 // be an overestimation if an app is not installed on the user on which the VPN is running, 500 // but that's safe. 501 final Set<Integer> changedUids = intersectUids(rangesToAdd, mAllApps); 502 removeBypassingUids(changedUids, vpnAppUid); 503 updateVpnUids(iface, changedUids, true); 504 if (mVpnUidRanges.containsKey(iface)) { 505 mVpnUidRanges.get(iface).addAll(rangesToAdd); 506 } else { 507 mVpnUidRanges.put(iface, new HashSet<UidRange>(rangesToAdd)); 508 } 509 } 510 511 /** 512 * Called when a set of UID ranges are removed from an active VPN network 513 * 514 * @param iface The VPN network's interface name 515 * @param rangesToRemove Existing UID ranges to be removed from the VPN network 516 * @param vpnAppUid The uid of the VPN app 517 */ onVpnUidRangesRemoved(@onNull String iface, Set<UidRange> rangesToRemove, int vpnAppUid)518 public synchronized void onVpnUidRangesRemoved(@NonNull String iface, 519 Set<UidRange> rangesToRemove, int vpnAppUid) { 520 // Calculate the list of app uids that are no longer under the VPN due to the removed UID 521 // ranges and update Netd about them. 522 final Set<Integer> changedUids = intersectUids(rangesToRemove, mAllApps); 523 removeBypassingUids(changedUids, vpnAppUid); 524 updateVpnUids(iface, changedUids, false); 525 Set<UidRange> existingRanges = mVpnUidRanges.getOrDefault(iface, null); 526 if (existingRanges == null) { 527 loge("Attempt to remove unknown vpn uid Range iface = " + iface); 528 return; 529 } 530 existingRanges.removeAll(rangesToRemove); 531 if (existingRanges.size() == 0) { 532 mVpnUidRanges.remove(iface); 533 } 534 } 535 536 /** 537 * Compute the intersection of a set of UidRanges and appIds. Returns a set of uids 538 * that satisfies: 539 * 1. falls into one of the UidRange 540 * 2. matches one of the appIds 541 */ intersectUids(Set<UidRange> ranges, Set<Integer> appIds)542 private Set<Integer> intersectUids(Set<UidRange> ranges, Set<Integer> appIds) { 543 Set<Integer> result = new HashSet<>(); 544 for (UidRange range : ranges) { 545 for (int userId = range.getStartUser(); userId <= range.getEndUser(); userId++) { 546 for (int appId : appIds) { 547 final int uid = UserHandle.getUid(userId, appId); 548 if (range.contains(uid)) { 549 result.add(uid); 550 } 551 } 552 } 553 } 554 return result; 555 } 556 557 /** 558 * Remove all apps which can elect to bypass the VPN from the list of uids 559 * 560 * An app can elect to bypass the VPN if it hold SYSTEM permission, or if its the active VPN 561 * app itself. 562 * 563 * @param uids The list of uids to operate on 564 * @param vpnAppUid The uid of the VPN app 565 */ removeBypassingUids(Set<Integer> uids, int vpnAppUid)566 private void removeBypassingUids(Set<Integer> uids, int vpnAppUid) { 567 uids.remove(vpnAppUid); 568 uids.removeIf(uid -> mApps.getOrDefault(uid, NETWORK) == SYSTEM); 569 } 570 571 /** 572 * Update netd about the list of uids that are under an active VPN connection which they cannot 573 * bypass. 574 * 575 * This is to instruct netd to set up appropriate filtering rules for these uids, such that they 576 * can only receive ingress packets from the VPN's tunnel interface (and loopback). 577 * 578 * @param iface the interface name of the active VPN connection 579 * @param add {@code true} if the uids are to be added to the interface, {@code false} if they 580 * are to be removed from the interface. 581 */ updateVpnUids(String iface, Set<Integer> uids, boolean add)582 private void updateVpnUids(String iface, Set<Integer> uids, boolean add) { 583 if (uids.size() == 0) { 584 return; 585 } 586 try { 587 if (add) { 588 mNetd.firewallAddUidInterfaceRules(iface, toIntArray(uids)); 589 } else { 590 mNetd.firewallRemoveUidInterfaceRules(toIntArray(uids)); 591 } 592 } catch (ServiceSpecificException e) { 593 // Silently ignore exception when device does not support eBPF, otherwise just log 594 // the exception and do not crash 595 if (e.errorCode != OsConstants.EOPNOTSUPP) { 596 loge("Exception when updating permissions: ", e); 597 } 598 } catch (RemoteException e) { 599 loge("Exception when updating permissions: ", e); 600 } 601 } 602 603 /** 604 * Called by PackageListObserver when a package is installed/uninstalled. Send the updated 605 * permission information to netd. 606 * 607 * @param uid the app uid of the package installed 608 * @param permissions the permissions the app requested and netd cares about. 609 * 610 * @hide 611 */ 612 @VisibleForTesting sendPackagePermissionsForUid(int uid, int permissions)613 void sendPackagePermissionsForUid(int uid, int permissions) { 614 SparseIntArray netdPermissionsAppIds = new SparseIntArray(); 615 netdPermissionsAppIds.put(uid, permissions); 616 sendPackagePermissionsToNetd(netdPermissionsAppIds); 617 } 618 619 /** 620 * Called by packageManagerService to send IPC to netd. Grant or revoke the INTERNET 621 * and/or UPDATE_DEVICE_STATS permission of the uids in array. 622 * 623 * @param netdPermissionsAppIds integer pairs of uids and the permission granted to it. If the 624 * permission is 0, revoke all permissions of that uid. 625 * 626 * @hide 627 */ 628 @VisibleForTesting sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds)629 void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) { 630 if (mNetd == null) { 631 Log.e(TAG, "Failed to get the netd service"); 632 return; 633 } 634 ArrayList<Integer> allPermissionAppIds = new ArrayList<>(); 635 ArrayList<Integer> internetPermissionAppIds = new ArrayList<>(); 636 ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>(); 637 ArrayList<Integer> noPermissionAppIds = new ArrayList<>(); 638 ArrayList<Integer> uninstalledAppIds = new ArrayList<>(); 639 for (int i = 0; i < netdPermissionsAppIds.size(); i++) { 640 int permissions = netdPermissionsAppIds.valueAt(i); 641 switch(permissions) { 642 case (INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS): 643 allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); 644 break; 645 case INetd.PERMISSION_INTERNET: 646 internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); 647 break; 648 case INetd.PERMISSION_UPDATE_DEVICE_STATS: 649 updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); 650 break; 651 case INetd.PERMISSION_NONE: 652 noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); 653 break; 654 case INetd.PERMISSION_UNINSTALLED: 655 uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i)); 656 default: 657 Log.e(TAG, "unknown permission type: " + permissions + "for uid: " 658 + netdPermissionsAppIds.keyAt(i)); 659 } 660 } 661 try { 662 // TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids() 663 if (allPermissionAppIds.size() != 0) { 664 mNetd.trafficSetNetPermForUids( 665 INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS, 666 ArrayUtils.convertToIntArray(allPermissionAppIds)); 667 } 668 if (internetPermissionAppIds.size() != 0) { 669 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET, 670 ArrayUtils.convertToIntArray(internetPermissionAppIds)); 671 } 672 if (updateStatsPermissionAppIds.size() != 0) { 673 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS, 674 ArrayUtils.convertToIntArray(updateStatsPermissionAppIds)); 675 } 676 if (noPermissionAppIds.size() != 0) { 677 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE, 678 ArrayUtils.convertToIntArray(noPermissionAppIds)); 679 } 680 if (uninstalledAppIds.size() != 0) { 681 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UNINSTALLED, 682 ArrayUtils.convertToIntArray(uninstalledAppIds)); 683 } 684 } catch (RemoteException e) { 685 Log.e(TAG, "Pass appId list of special permission failed." + e); 686 } 687 } 688 689 /** Should only be used by unit tests */ 690 @VisibleForTesting getVpnUidRanges(String iface)691 public Set<UidRange> getVpnUidRanges(String iface) { 692 return mVpnUidRanges.get(iface); 693 } 694 695 /** Dump info to dumpsys */ dump(IndentingPrintWriter pw)696 public void dump(IndentingPrintWriter pw) { 697 pw.println("Interface filtering rules:"); 698 pw.increaseIndent(); 699 for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) { 700 pw.println("Interface: " + vpn.getKey()); 701 pw.println("UIDs: " + vpn.getValue().toString()); 702 pw.println(); 703 } 704 pw.decreaseIndent(); 705 } 706 log(String s)707 private static void log(String s) { 708 if (DBG) { 709 Log.d(TAG, s); 710 } 711 } 712 loge(String s)713 private static void loge(String s) { 714 Log.e(TAG, s); 715 } 716 loge(String s, Throwable e)717 private static void loge(String s, Throwable e) { 718 Log.e(TAG, s, e); 719 } 720 } 721