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