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.ConnectivitySettingsManager.UIDS_ALLOWED_ON_RESTRICTED_NETWORKS; 28 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; 29 import static android.os.Process.INVALID_UID; 30 import static android.os.Process.SYSTEM_UID; 31 32 import static com.android.net.module.util.CollectionUtils.toIntArray; 33 34 import android.annotation.NonNull; 35 import android.content.BroadcastReceiver; 36 import android.content.Context; 37 import android.content.Intent; 38 import android.content.IntentFilter; 39 import android.content.pm.ApplicationInfo; 40 import android.content.pm.PackageInfo; 41 import android.content.pm.PackageManager; 42 import android.content.pm.PackageManager.NameNotFoundException; 43 import android.database.ContentObserver; 44 import android.net.ConnectivitySettingsManager; 45 import android.net.INetd; 46 import android.net.UidRange; 47 import android.net.Uri; 48 import android.os.Build; 49 import android.os.RemoteException; 50 import android.os.ServiceSpecificException; 51 import android.os.SystemConfigManager; 52 import android.os.UserHandle; 53 import android.os.UserManager; 54 import android.provider.Settings; 55 import android.system.OsConstants; 56 import android.util.ArraySet; 57 import android.util.Log; 58 import android.util.SparseArray; 59 import android.util.SparseIntArray; 60 61 import com.android.internal.annotations.GuardedBy; 62 import com.android.internal.annotations.VisibleForTesting; 63 import com.android.internal.util.IndentingPrintWriter; 64 import com.android.net.module.util.CollectionUtils; 65 66 import java.util.ArrayList; 67 import java.util.HashMap; 68 import java.util.HashSet; 69 import java.util.List; 70 import java.util.Map; 71 import java.util.Map.Entry; 72 import java.util.Set; 73 74 /** 75 * A utility class to inform Netd of UID permisisons. 76 * Does a mass update at boot and then monitors for app install/remove. 77 * 78 * @hide 79 */ 80 public class PermissionMonitor { 81 private static final String TAG = "PermissionMonitor"; 82 private static final boolean DBG = true; 83 protected static final Boolean SYSTEM = Boolean.TRUE; 84 protected static final Boolean NETWORK = Boolean.FALSE; 85 private static final int VERSION_Q = Build.VERSION_CODES.Q; 86 87 private final PackageManager mPackageManager; 88 private final UserManager mUserManager; 89 private final SystemConfigManager mSystemConfigManager; 90 private final INetd mNetd; 91 private final Dependencies mDeps; 92 private final Context mContext; 93 94 @GuardedBy("this") 95 private final Set<UserHandle> mUsers = new HashSet<>(); 96 97 // Keys are app uids. Values are true for SYSTEM permission and false for NETWORK permission. 98 @GuardedBy("this") 99 private final Map<Integer, Boolean> mApps = new HashMap<>(); 100 101 // Keys are active non-bypassable and fully-routed VPN's interface name, Values are uid ranges 102 // for apps under the VPN 103 @GuardedBy("this") 104 private final Map<String, Set<UidRange>> mVpnUidRanges = new HashMap<>(); 105 106 // A set of appIds for apps across all users on the device. We track appIds instead of uids 107 // directly to reduce its size and also eliminate the need to update this set when user is 108 // added/removed. 109 @GuardedBy("this") 110 private final Set<Integer> mAllApps = new HashSet<>(); 111 112 // A set of uids which are allowed to use restricted networks. The packages of these uids can't 113 // hold the CONNECTIVITY_USE_RESTRICTED_NETWORKS permission because they can't be 114 // signature|privileged apps. However, these apps should still be able to use restricted 115 // networks under certain conditions (e.g. government app using emergency services). So grant 116 // netd system permission to these uids which is listed in UIDS_ALLOWED_ON_RESTRICTED_NETWORKS. 117 @GuardedBy("this") 118 private final Set<Integer> mUidsAllowedOnRestrictedNetworks = new ArraySet<>(); 119 120 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 121 @Override 122 public void onReceive(Context context, Intent intent) { 123 final String action = intent.getAction(); 124 125 if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { 126 final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); 127 final Uri packageData = intent.getData(); 128 final String packageName = 129 packageData != null ? packageData.getSchemeSpecificPart() : null; 130 onPackageAdded(packageName, uid); 131 } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { 132 final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); 133 final Uri packageData = intent.getData(); 134 final String packageName = 135 packageData != null ? packageData.getSchemeSpecificPart() : null; 136 onPackageRemoved(packageName, uid); 137 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { 138 final String[] pkgList = 139 intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 140 onExternalApplicationsAvailable(pkgList); 141 } else { 142 Log.wtf(TAG, "received unexpected intent: " + action); 143 } 144 } 145 }; 146 147 /** 148 * Dependencies of PermissionMonitor, for injection in tests. 149 */ 150 @VisibleForTesting 151 public static class Dependencies { 152 /** 153 * Get device first sdk version. 154 */ getDeviceFirstSdkInt()155 public int getDeviceFirstSdkInt() { 156 return Build.VERSION.DEVICE_INITIAL_SDK_INT; 157 } 158 159 /** 160 * Get uids allowed to use restricted networks via ConnectivitySettingsManager. 161 */ getUidsAllowedOnRestrictedNetworks(@onNull Context context)162 public Set<Integer> getUidsAllowedOnRestrictedNetworks(@NonNull Context context) { 163 return ConnectivitySettingsManager.getUidsAllowedOnRestrictedNetworks(context); 164 } 165 166 /** 167 * Register ContentObserver for given Uri. 168 */ registerContentObserver(@onNull Context context, @NonNull Uri uri, boolean notifyForDescendants, @NonNull ContentObserver observer)169 public void registerContentObserver(@NonNull Context context, @NonNull Uri uri, 170 boolean notifyForDescendants, @NonNull ContentObserver observer) { 171 context.getContentResolver().registerContentObserver( 172 uri, notifyForDescendants, observer); 173 } 174 } 175 PermissionMonitor(@onNull final Context context, @NonNull final INetd netd)176 public PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd) { 177 this(context, netd, new Dependencies()); 178 } 179 180 @VisibleForTesting PermissionMonitor(@onNull final Context context, @NonNull final INetd netd, @NonNull final Dependencies deps)181 PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd, 182 @NonNull final Dependencies deps) { 183 mPackageManager = context.getPackageManager(); 184 mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 185 mSystemConfigManager = context.getSystemService(SystemConfigManager.class); 186 mNetd = netd; 187 mDeps = deps; 188 mContext = context; 189 } 190 191 // Intended to be called only once at startup, after the system is ready. Installs a broadcast 192 // receiver to monitor ongoing UID changes, so this shouldn't/needn't be called again. startMonitoring()193 public synchronized void startMonitoring() { 194 log("Monitoring"); 195 196 final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */); 197 final IntentFilter intentFilter = new IntentFilter(); 198 intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 199 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 200 intentFilter.addDataScheme("package"); 201 userAllContext.registerReceiver( 202 mIntentReceiver, intentFilter, null /* broadcastPermission */, 203 null /* scheduler */); 204 205 final IntentFilter externalIntentFilter = 206 new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 207 userAllContext.registerReceiver( 208 mIntentReceiver, externalIntentFilter, null /* broadcastPermission */, 209 null /* scheduler */); 210 211 // Register UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting observer 212 mDeps.registerContentObserver( 213 userAllContext, 214 Settings.Global.getUriFor(UIDS_ALLOWED_ON_RESTRICTED_NETWORKS), 215 false /* notifyForDescendants */, 216 new ContentObserver(null) { 217 @Override 218 public void onChange(boolean selfChange) { 219 onSettingChanged(); 220 } 221 }); 222 223 // Read UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting and update 224 // mUidsAllowedOnRestrictedNetworks. 225 updateUidsAllowedOnRestrictedNetworks(mDeps.getUidsAllowedOnRestrictedNetworks(mContext)); 226 227 List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS 228 | MATCH_ANY_USER); 229 if (apps == null) { 230 loge("No apps"); 231 return; 232 } 233 234 SparseIntArray netdPermsUids = new SparseIntArray(); 235 236 for (PackageInfo app : apps) { 237 int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID; 238 if (uid < 0) { 239 continue; 240 } 241 mAllApps.add(UserHandle.getAppId(uid)); 242 243 boolean isNetwork = hasNetworkPermission(app); 244 boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app); 245 246 if (isNetwork || hasRestrictedPermission) { 247 Boolean permission = mApps.get(UserHandle.getAppId(uid)); 248 // If multiple packages share a UID (cf: android:sharedUserId) and ask for different 249 // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is). 250 if (permission == null || permission == NETWORK) { 251 mApps.put(UserHandle.getAppId(uid), hasRestrictedPermission); 252 } 253 } 254 255 //TODO: unify the management of the permissions into one codepath. 256 int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions, 257 app.requestedPermissionsFlags); 258 netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms); 259 } 260 261 mUsers.addAll(mUserManager.getUserHandles(true /* excludeDying */)); 262 263 final SparseArray<String> netdPermToSystemPerm = new SparseArray<>(); 264 netdPermToSystemPerm.put(INetd.PERMISSION_INTERNET, INTERNET); 265 netdPermToSystemPerm.put(INetd.PERMISSION_UPDATE_DEVICE_STATS, UPDATE_DEVICE_STATS); 266 for (int i = 0; i < netdPermToSystemPerm.size(); i++) { 267 final int netdPermission = netdPermToSystemPerm.keyAt(i); 268 final String systemPermission = netdPermToSystemPerm.valueAt(i); 269 final int[] hasPermissionUids = 270 mSystemConfigManager.getSystemPermissionUids(systemPermission); 271 for (int j = 0; j < hasPermissionUids.length; j++) { 272 final int uid = hasPermissionUids[j]; 273 netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission); 274 } 275 } 276 log("Users: " + mUsers.size() + ", Apps: " + mApps.size()); 277 update(mUsers, mApps, true); 278 sendPackagePermissionsToNetd(netdPermsUids); 279 } 280 281 @VisibleForTesting updateUidsAllowedOnRestrictedNetworks(final Set<Integer> uids)282 synchronized void updateUidsAllowedOnRestrictedNetworks(final Set<Integer> uids) { 283 mUidsAllowedOnRestrictedNetworks.clear(); 284 // This is necessary for the app id to match in isUidAllowedOnRestrictedNetworks, and will 285 // grant the permission to all uids associated with the app ID. This is safe even if the app 286 // is only installed on some users because the uid cannot match some other app – this uid is 287 // in effect not installed and can't be run. 288 // TODO (b/192431153): Change appIds back to uids. 289 for (int uid : uids) { 290 mUidsAllowedOnRestrictedNetworks.add(UserHandle.getAppId(uid)); 291 } 292 } 293 294 @VisibleForTesting isVendorApp(@onNull ApplicationInfo appInfo)295 static boolean isVendorApp(@NonNull ApplicationInfo appInfo) { 296 return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct(); 297 } 298 299 @VisibleForTesting isCarryoverPackage(final ApplicationInfo appInfo)300 boolean isCarryoverPackage(final ApplicationInfo appInfo) { 301 if (appInfo == null) return false; 302 return (appInfo.targetSdkVersion < VERSION_Q && isVendorApp(appInfo)) 303 // Backward compatibility for b/114245686, on devices that launched before Q daemons 304 // and apps running as the system UID are exempted from this check. 305 || (appInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q); 306 } 307 308 @VisibleForTesting isUidAllowedOnRestrictedNetworks(final ApplicationInfo appInfo)309 synchronized boolean isUidAllowedOnRestrictedNetworks(final ApplicationInfo appInfo) { 310 if (appInfo == null) return false; 311 // Check whether package's uid is in allowed on restricted networks uid list. If so, this 312 // uid can have netd system permission. 313 return mUidsAllowedOnRestrictedNetworks.contains(UserHandle.getAppId(appInfo.uid)); 314 } 315 316 @VisibleForTesting hasPermission(@onNull final PackageInfo app, @NonNull final String permission)317 boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) { 318 if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) { 319 return false; 320 } 321 final int index = CollectionUtils.indexOf(app.requestedPermissions, permission); 322 if (index < 0 || index >= app.requestedPermissionsFlags.length) return false; 323 return (app.requestedPermissionsFlags[index] & REQUESTED_PERMISSION_GRANTED) != 0; 324 } 325 326 @VisibleForTesting hasNetworkPermission(@onNull final PackageInfo app)327 boolean hasNetworkPermission(@NonNull final PackageInfo app) { 328 return hasPermission(app, CHANGE_NETWORK_STATE); 329 } 330 331 @VisibleForTesting hasRestrictedNetworkPermission(@onNull final PackageInfo app)332 boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) { 333 // TODO : remove carryover package check in the future(b/31479477). All apps should just 334 // request the appropriate permission for their use case since android Q. 335 return isCarryoverPackage(app.applicationInfo) 336 || isUidAllowedOnRestrictedNetworks(app.applicationInfo) 337 || hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK) 338 || hasPermission(app, NETWORK_STACK) 339 || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS); 340 } 341 342 /** Returns whether the given uid has using background network permission. */ hasUseBackgroundNetworksPermission(final int uid)343 public synchronized boolean hasUseBackgroundNetworksPermission(final int uid) { 344 // Apps with any of the CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_INTERNAL or 345 // CONNECTIVITY_USE_RESTRICTED_NETWORKS permission has the permission to use background 346 // networks. mApps contains the result of checks for both hasNetworkPermission and 347 // hasRestrictedNetworkPermission. If uid is in the mApps list that means uid has one of 348 // permissions at least. 349 return mApps.containsKey(UserHandle.getAppId(uid)); 350 } 351 352 /** 353 * Returns whether the given uid has permission to use restricted networks. 354 */ hasRestrictedNetworksPermission(int uid)355 public synchronized boolean hasRestrictedNetworksPermission(int uid) { 356 return Boolean.TRUE.equals(mApps.get(UserHandle.getAppId(uid))); 357 } 358 update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add)359 private void update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add) { 360 List<Integer> network = new ArrayList<>(); 361 List<Integer> system = new ArrayList<>(); 362 for (Entry<Integer, Boolean> app : apps.entrySet()) { 363 List<Integer> list = app.getValue() ? system : network; 364 for (UserHandle user : users) { 365 if (user == null) continue; 366 367 list.add(user.getUid(app.getKey())); 368 } 369 } 370 try { 371 if (add) { 372 mNetd.networkSetPermissionForUser(INetd.PERMISSION_NETWORK, toIntArray(network)); 373 mNetd.networkSetPermissionForUser(INetd.PERMISSION_SYSTEM, toIntArray(system)); 374 } else { 375 mNetd.networkClearPermissionForUser(toIntArray(network)); 376 mNetd.networkClearPermissionForUser(toIntArray(system)); 377 } 378 } catch (RemoteException e) { 379 loge("Exception when updating permissions: " + e); 380 } 381 } 382 383 /** 384 * Called when a user is added. See {link #ACTION_USER_ADDED}. 385 * 386 * @param user The integer userHandle of the added user. See {@link #EXTRA_USER_HANDLE}. 387 * 388 * @hide 389 */ onUserAdded(@onNull UserHandle user)390 public synchronized void onUserAdded(@NonNull UserHandle user) { 391 mUsers.add(user); 392 393 Set<UserHandle> users = new HashSet<>(); 394 users.add(user); 395 update(users, mApps, true); 396 } 397 398 /** 399 * Called when an user is removed. See {link #ACTION_USER_REMOVED}. 400 * 401 * @param user The integer userHandle of the removed user. See {@link #EXTRA_USER_HANDLE}. 402 * 403 * @hide 404 */ onUserRemoved(@onNull UserHandle user)405 public synchronized void onUserRemoved(@NonNull UserHandle user) { 406 mUsers.remove(user); 407 408 Set<UserHandle> users = new HashSet<>(); 409 users.add(user); 410 update(users, mApps, false); 411 } 412 413 /** 414 * Compare the current network permission and the given package's permission to find out highest 415 * permission for the uid. 416 * 417 * @param currentPermission Current uid network permission 418 * @param name The package has same uid that need compare its permission to update uid network 419 * permission. 420 */ 421 @VisibleForTesting highestPermissionForUid(Boolean currentPermission, String name)422 protected Boolean highestPermissionForUid(Boolean currentPermission, String name) { 423 if (currentPermission == SYSTEM) { 424 return currentPermission; 425 } 426 try { 427 final PackageInfo app = mPackageManager.getPackageInfo(name, 428 GET_PERMISSIONS | MATCH_ANY_USER); 429 final boolean isNetwork = hasNetworkPermission(app); 430 final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app); 431 if (isNetwork || hasRestrictedPermission) { 432 currentPermission = hasRestrictedPermission; 433 } 434 } catch (NameNotFoundException e) { 435 // App not found. 436 loge("NameNotFoundException " + name); 437 } 438 return currentPermission; 439 } 440 getPermissionForUid(final int uid)441 private int getPermissionForUid(final int uid) { 442 int permission = INetd.PERMISSION_NONE; 443 // Check all the packages for this UID. The UID has the permission if any of the 444 // packages in it has the permission. 445 final String[] packages = mPackageManager.getPackagesForUid(uid); 446 if (packages != null && packages.length > 0) { 447 for (String name : packages) { 448 final PackageInfo app = getPackageInfo(name); 449 if (app != null && app.requestedPermissions != null) { 450 permission |= getNetdPermissionMask(app.requestedPermissions, 451 app.requestedPermissionsFlags); 452 } 453 } 454 } else { 455 // The last package of this uid is removed from device. Clean the package up. 456 permission = INetd.PERMISSION_UNINSTALLED; 457 } 458 return permission; 459 } 460 461 /** 462 * Called when a package is added. 463 * 464 * @param packageName The name of the new package. 465 * @param uid The uid of the new package. 466 * 467 * @hide 468 */ onPackageAdded(@onNull final String packageName, final int uid)469 public synchronized void onPackageAdded(@NonNull final String packageName, final int uid) { 470 // TODO: Netd is using appId for checking traffic permission. Correct the methods that are 471 // using appId instead of uid actually 472 sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid)); 473 474 // If multiple packages share a UID (cf: android:sharedUserId) and ask for different 475 // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is). 476 final int appId = UserHandle.getAppId(uid); 477 final Boolean permission = highestPermissionForUid(mApps.get(appId), packageName); 478 if (permission != mApps.get(appId)) { 479 mApps.put(appId, permission); 480 481 Map<Integer, Boolean> apps = new HashMap<>(); 482 apps.put(appId, permission); 483 update(mUsers, apps, true); 484 } 485 486 // If the newly-installed package falls within some VPN's uid range, update Netd with it. 487 // This needs to happen after the mApps update above, since removeBypassingUids() depends 488 // on mApps to check if the package can bypass VPN. 489 for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) { 490 if (UidRange.containsUid(vpn.getValue(), uid)) { 491 final Set<Integer> changedUids = new HashSet<>(); 492 changedUids.add(uid); 493 removeBypassingUids(changedUids, /* vpnAppUid */ -1); 494 updateVpnUids(vpn.getKey(), changedUids, true); 495 } 496 } 497 mAllApps.add(appId); 498 } 499 highestUidNetworkPermission(int uid)500 private Boolean highestUidNetworkPermission(int uid) { 501 Boolean permission = null; 502 final String[] packages = mPackageManager.getPackagesForUid(uid); 503 if (!CollectionUtils.isEmpty(packages)) { 504 for (String name : packages) { 505 // If multiple packages have the same UID, give the UID all permissions that 506 // any package in that UID has. 507 permission = highestPermissionForUid(permission, name); 508 if (permission == SYSTEM) { 509 break; 510 } 511 } 512 } 513 return permission; 514 } 515 516 /** 517 * Called when a package is removed. 518 * 519 * @param packageName The name of the removed package or null. 520 * @param uid containing the integer uid previously assigned to the package. 521 * 522 * @hide 523 */ onPackageRemoved(@onNull final String packageName, final int uid)524 public synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) { 525 // TODO: Netd is using appId for checking traffic permission. Correct the methods that are 526 // using appId instead of uid actually 527 sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid)); 528 529 // If the newly-removed package falls within some VPN's uid range, update Netd with it. 530 // This needs to happen before the mApps update below, since removeBypassingUids() depends 531 // on mApps to check if the package can bypass VPN. 532 for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) { 533 if (UidRange.containsUid(vpn.getValue(), uid)) { 534 final Set<Integer> changedUids = new HashSet<>(); 535 changedUids.add(uid); 536 removeBypassingUids(changedUids, /* vpnAppUid */ -1); 537 updateVpnUids(vpn.getKey(), changedUids, false); 538 } 539 } 540 // If the package has been removed from all users on the device, clear it form mAllApps. 541 if (mPackageManager.getNameForUid(uid) == null) { 542 mAllApps.remove(UserHandle.getAppId(uid)); 543 } 544 545 Map<Integer, Boolean> apps = new HashMap<>(); 546 final Boolean permission = highestUidNetworkPermission(uid); 547 if (permission == SYSTEM) { 548 // An app with this UID still has the SYSTEM permission. 549 // Therefore, this UID must already have the SYSTEM permission. 550 // Nothing to do. 551 return; 552 } 553 554 final int appId = UserHandle.getAppId(uid); 555 if (permission == mApps.get(appId)) { 556 // The permissions of this UID have not changed. Nothing to do. 557 return; 558 } else if (permission != null) { 559 mApps.put(appId, permission); 560 apps.put(appId, permission); 561 update(mUsers, apps, true); 562 } else { 563 mApps.remove(appId); 564 apps.put(appId, NETWORK); // doesn't matter which permission we pick here 565 update(mUsers, apps, false); 566 } 567 } 568 getNetdPermissionMask(String[] requestedPermissions, int[] requestedPermissionsFlags)569 private static int getNetdPermissionMask(String[] requestedPermissions, 570 int[] requestedPermissionsFlags) { 571 int permissions = 0; 572 if (requestedPermissions == null || requestedPermissionsFlags == null) return permissions; 573 for (int i = 0; i < requestedPermissions.length; i++) { 574 if (requestedPermissions[i].equals(INTERNET) 575 && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) { 576 permissions |= INetd.PERMISSION_INTERNET; 577 } 578 if (requestedPermissions[i].equals(UPDATE_DEVICE_STATS) 579 && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) { 580 permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS; 581 } 582 } 583 return permissions; 584 } 585 getPackageInfo(String packageName)586 private PackageInfo getPackageInfo(String packageName) { 587 try { 588 PackageInfo app = mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS 589 | MATCH_ANY_USER); 590 return app; 591 } catch (NameNotFoundException e) { 592 return null; 593 } 594 } 595 596 /** 597 * Called when a new set of UID ranges are added to an active VPN network 598 * 599 * @param iface The active VPN network's interface name 600 * @param rangesToAdd The new UID ranges to be added to the network 601 * @param vpnAppUid The uid of the VPN app 602 */ onVpnUidRangesAdded(@onNull String iface, Set<UidRange> rangesToAdd, int vpnAppUid)603 public synchronized void onVpnUidRangesAdded(@NonNull String iface, Set<UidRange> rangesToAdd, 604 int vpnAppUid) { 605 // Calculate the list of new app uids under the VPN due to the new UID ranges and update 606 // Netd about them. Because mAllApps only contains appIds instead of uids, the result might 607 // be an overestimation if an app is not installed on the user on which the VPN is running, 608 // but that's safe. 609 final Set<Integer> changedUids = intersectUids(rangesToAdd, mAllApps); 610 removeBypassingUids(changedUids, vpnAppUid); 611 updateVpnUids(iface, changedUids, true); 612 if (mVpnUidRanges.containsKey(iface)) { 613 mVpnUidRanges.get(iface).addAll(rangesToAdd); 614 } else { 615 mVpnUidRanges.put(iface, new HashSet<UidRange>(rangesToAdd)); 616 } 617 } 618 619 /** 620 * Called when a set of UID ranges are removed from an active VPN network 621 * 622 * @param iface The VPN network's interface name 623 * @param rangesToRemove Existing UID ranges to be removed from the VPN network 624 * @param vpnAppUid The uid of the VPN app 625 */ onVpnUidRangesRemoved(@onNull String iface, Set<UidRange> rangesToRemove, int vpnAppUid)626 public synchronized void onVpnUidRangesRemoved(@NonNull String iface, 627 Set<UidRange> rangesToRemove, int vpnAppUid) { 628 // Calculate the list of app uids that are no longer under the VPN due to the removed UID 629 // ranges and update Netd about them. 630 final Set<Integer> changedUids = intersectUids(rangesToRemove, mAllApps); 631 removeBypassingUids(changedUids, vpnAppUid); 632 updateVpnUids(iface, changedUids, false); 633 Set<UidRange> existingRanges = mVpnUidRanges.getOrDefault(iface, null); 634 if (existingRanges == null) { 635 loge("Attempt to remove unknown vpn uid Range iface = " + iface); 636 return; 637 } 638 existingRanges.removeAll(rangesToRemove); 639 if (existingRanges.size() == 0) { 640 mVpnUidRanges.remove(iface); 641 } 642 } 643 644 /** 645 * Compute the intersection of a set of UidRanges and appIds. Returns a set of uids 646 * that satisfies: 647 * 1. falls into one of the UidRange 648 * 2. matches one of the appIds 649 */ intersectUids(Set<UidRange> ranges, Set<Integer> appIds)650 private Set<Integer> intersectUids(Set<UidRange> ranges, Set<Integer> appIds) { 651 Set<Integer> result = new HashSet<>(); 652 for (UidRange range : ranges) { 653 for (int userId = range.getStartUser(); userId <= range.getEndUser(); userId++) { 654 for (int appId : appIds) { 655 final UserHandle handle = UserHandle.of(userId); 656 if (handle == null) continue; 657 658 final int uid = handle.getUid(appId); 659 if (range.contains(uid)) { 660 result.add(uid); 661 } 662 } 663 } 664 } 665 return result; 666 } 667 668 /** 669 * Remove all apps which can elect to bypass the VPN from the list of uids 670 * 671 * An app can elect to bypass the VPN if it hold SYSTEM permission, or if its the active VPN 672 * app itself. 673 * 674 * @param uids The list of uids to operate on 675 * @param vpnAppUid The uid of the VPN app 676 */ removeBypassingUids(Set<Integer> uids, int vpnAppUid)677 private void removeBypassingUids(Set<Integer> uids, int vpnAppUid) { 678 uids.remove(vpnAppUid); 679 uids.removeIf(uid -> mApps.getOrDefault(UserHandle.getAppId(uid), NETWORK) == SYSTEM); 680 } 681 682 /** 683 * Update netd about the list of uids that are under an active VPN connection which they cannot 684 * bypass. 685 * 686 * This is to instruct netd to set up appropriate filtering rules for these uids, such that they 687 * can only receive ingress packets from the VPN's tunnel interface (and loopback). 688 * 689 * @param iface the interface name of the active VPN connection 690 * @param add {@code true} if the uids are to be added to the interface, {@code false} if they 691 * are to be removed from the interface. 692 */ updateVpnUids(String iface, Set<Integer> uids, boolean add)693 private void updateVpnUids(String iface, Set<Integer> uids, boolean add) { 694 if (uids.size() == 0) { 695 return; 696 } 697 try { 698 if (add) { 699 mNetd.firewallAddUidInterfaceRules(iface, toIntArray(uids)); 700 } else { 701 mNetd.firewallRemoveUidInterfaceRules(toIntArray(uids)); 702 } 703 } catch (ServiceSpecificException e) { 704 // Silently ignore exception when device does not support eBPF, otherwise just log 705 // the exception and do not crash 706 if (e.errorCode != OsConstants.EOPNOTSUPP) { 707 loge("Exception when updating permissions: ", e); 708 } 709 } catch (RemoteException e) { 710 loge("Exception when updating permissions: ", e); 711 } 712 } 713 714 /** 715 * Called by PackageListObserver when a package is installed/uninstalled. Send the updated 716 * permission information to netd. 717 * 718 * @param uid the app uid of the package installed 719 * @param permissions the permissions the app requested and netd cares about. 720 * 721 * @hide 722 */ 723 @VisibleForTesting sendPackagePermissionsForUid(int uid, int permissions)724 void sendPackagePermissionsForUid(int uid, int permissions) { 725 SparseIntArray netdPermissionsAppIds = new SparseIntArray(); 726 netdPermissionsAppIds.put(uid, permissions); 727 sendPackagePermissionsToNetd(netdPermissionsAppIds); 728 } 729 730 /** 731 * Called by packageManagerService to send IPC to netd. Grant or revoke the INTERNET 732 * and/or UPDATE_DEVICE_STATS permission of the uids in array. 733 * 734 * @param netdPermissionsAppIds integer pairs of uids and the permission granted to it. If the 735 * permission is 0, revoke all permissions of that uid. 736 * 737 * @hide 738 */ 739 @VisibleForTesting sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds)740 void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) { 741 if (mNetd == null) { 742 Log.e(TAG, "Failed to get the netd service"); 743 return; 744 } 745 ArrayList<Integer> allPermissionAppIds = new ArrayList<>(); 746 ArrayList<Integer> internetPermissionAppIds = new ArrayList<>(); 747 ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>(); 748 ArrayList<Integer> noPermissionAppIds = new ArrayList<>(); 749 ArrayList<Integer> uninstalledAppIds = new ArrayList<>(); 750 for (int i = 0; i < netdPermissionsAppIds.size(); i++) { 751 int permissions = netdPermissionsAppIds.valueAt(i); 752 switch(permissions) { 753 case (INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS): 754 allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); 755 break; 756 case INetd.PERMISSION_INTERNET: 757 internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); 758 break; 759 case INetd.PERMISSION_UPDATE_DEVICE_STATS: 760 updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); 761 break; 762 case INetd.PERMISSION_NONE: 763 noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); 764 break; 765 case INetd.PERMISSION_UNINSTALLED: 766 uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i)); 767 break; 768 default: 769 Log.e(TAG, "unknown permission type: " + permissions + "for uid: " 770 + netdPermissionsAppIds.keyAt(i)); 771 } 772 } 773 try { 774 // TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids() 775 if (allPermissionAppIds.size() != 0) { 776 mNetd.trafficSetNetPermForUids( 777 INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS, 778 toIntArray(allPermissionAppIds)); 779 } 780 if (internetPermissionAppIds.size() != 0) { 781 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET, 782 toIntArray(internetPermissionAppIds)); 783 } 784 if (updateStatsPermissionAppIds.size() != 0) { 785 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS, 786 toIntArray(updateStatsPermissionAppIds)); 787 } 788 if (noPermissionAppIds.size() != 0) { 789 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE, 790 toIntArray(noPermissionAppIds)); 791 } 792 if (uninstalledAppIds.size() != 0) { 793 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UNINSTALLED, 794 toIntArray(uninstalledAppIds)); 795 } 796 } catch (RemoteException e) { 797 Log.e(TAG, "Pass appId list of special permission failed." + e); 798 } 799 } 800 801 /** Should only be used by unit tests */ 802 @VisibleForTesting getVpnUidRanges(String iface)803 public Set<UidRange> getVpnUidRanges(String iface) { 804 return mVpnUidRanges.get(iface); 805 } 806 onSettingChanged()807 private synchronized void onSettingChanged() { 808 // Step1. Update uids allowed to use restricted networks and compute the set of uids to 809 // update. 810 final Set<Integer> uidsToUpdate = new ArraySet<>(mUidsAllowedOnRestrictedNetworks); 811 updateUidsAllowedOnRestrictedNetworks(mDeps.getUidsAllowedOnRestrictedNetworks(mContext)); 812 uidsToUpdate.addAll(mUidsAllowedOnRestrictedNetworks); 813 814 final Map<Integer, Boolean> updatedUids = new HashMap<>(); 815 final Map<Integer, Boolean> removedUids = new HashMap<>(); 816 817 // Step2. For each uid to update, find out its new permission. 818 for (Integer uid : uidsToUpdate) { 819 final Boolean permission = highestUidNetworkPermission(uid); 820 821 final int appId = UserHandle.getAppId(uid); 822 if (null == permission) { 823 removedUids.put(appId, NETWORK); // Doesn't matter which permission is set here. 824 mApps.remove(appId); 825 } else { 826 updatedUids.put(appId, permission); 827 mApps.put(appId, permission); 828 } 829 } 830 831 // Step3. Update or revoke permission for uids with netd. 832 update(mUsers, updatedUids, true /* add */); 833 update(mUsers, removedUids, false /* add */); 834 } 835 onExternalApplicationsAvailable(String[] pkgList)836 private synchronized void onExternalApplicationsAvailable(String[] pkgList) { 837 if (CollectionUtils.isEmpty(pkgList)) { 838 Log.e(TAG, "No available external application."); 839 return; 840 } 841 842 for (String app : pkgList) { 843 final PackageInfo info = getPackageInfo(app); 844 if (info == null || info.applicationInfo == null) continue; 845 846 final int appId = info.applicationInfo.uid; 847 onPackageAdded(app, appId); // Use onPackageAdded to add package one by one. 848 } 849 } 850 851 /** Dump info to dumpsys */ dump(IndentingPrintWriter pw)852 public void dump(IndentingPrintWriter pw) { 853 pw.println("Interface filtering rules:"); 854 pw.increaseIndent(); 855 for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) { 856 pw.println("Interface: " + vpn.getKey()); 857 pw.println("UIDs: " + vpn.getValue().toString()); 858 pw.println(); 859 } 860 pw.decreaseIndent(); 861 } 862 log(String s)863 private static void log(String s) { 864 if (DBG) { 865 Log.d(TAG, s); 866 } 867 } 868 loge(String s)869 private static void loge(String s) { 870 Log.e(TAG, s); 871 } 872 loge(String s, Throwable e)873 private static void loge(String s, Throwable e) { 874 Log.e(TAG, s, e); 875 } 876 } 877