1 /* 2 * Copyright (C) 2016 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.wifi.util; 18 19 import android.Manifest; 20 import android.annotation.Nullable; 21 import android.app.AppOpsManager; 22 import android.app.admin.DevicePolicyManager; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.pm.ApplicationInfo; 26 import android.content.pm.PackageManager; 27 import android.location.LocationManager; 28 import android.net.NetworkStack; 29 import android.os.Binder; 30 import android.os.Build; 31 import android.os.UserHandle; 32 import android.os.UserManager; 33 import android.provider.Settings; 34 import android.util.EventLog; 35 import android.util.Log; 36 import android.util.Pair; 37 38 import com.android.internal.annotations.GuardedBy; 39 import com.android.modules.utils.build.SdkLevel; 40 import com.android.server.wifi.FrameworkFacade; 41 import com.android.server.wifi.WifiInjector; 42 import com.android.server.wifi.WifiLog; 43 44 import java.util.Arrays; 45 46 /** 47 * A wifi permissions utility assessing permissions 48 * for getting scan results by a package. 49 */ 50 public class WifiPermissionsUtil { 51 private static final String TAG = "WifiPermissionsUtil"; 52 53 private static final int APP_INFO_FLAGS_SYSTEM_APP = 54 ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; 55 private final WifiPermissionsWrapper mWifiPermissionsWrapper; 56 private final Context mContext; 57 private final FrameworkFacade mFrameworkFacade; 58 private final AppOpsManager mAppOps; 59 private final UserManager mUserManager; 60 private final Object mLock = new Object(); 61 @GuardedBy("mLock") 62 private LocationManager mLocationManager; 63 private WifiLog mLog; 64 private boolean mVerboseLoggingEnabled; 65 WifiPermissionsUtil(WifiPermissionsWrapper wifiPermissionsWrapper, Context context, UserManager userManager, WifiInjector wifiInjector)66 public WifiPermissionsUtil(WifiPermissionsWrapper wifiPermissionsWrapper, 67 Context context, UserManager userManager, WifiInjector wifiInjector) { 68 mWifiPermissionsWrapper = wifiPermissionsWrapper; 69 mContext = context; 70 mFrameworkFacade = wifiInjector.getFrameworkFacade(); 71 mUserManager = userManager; 72 mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 73 mLog = wifiInjector.makeLog(TAG); 74 } 75 76 /** 77 * Checks if the app has the permission to override Wi-Fi network configuration or not. 78 * 79 * @param uid uid of the app. 80 * @return true if the app does have the permission, false otherwise. 81 */ checkConfigOverridePermission(int uid)82 public boolean checkConfigOverridePermission(int uid) { 83 int permission = mWifiPermissionsWrapper.getOverrideWifiConfigPermission(uid); 84 return permission == PackageManager.PERMISSION_GRANTED; 85 } 86 87 /** 88 * Check and enforce Coarse or Fine Location permission (depending on target SDK). 89 * 90 * @param pkgName PackageName of the application requesting access 91 * @param featureId The feature in the package 92 * @param uid The uid of the package 93 */ enforceLocationPermission(String pkgName, @Nullable String featureId, int uid)94 public void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid) { 95 if (!checkCallersLocationPermission(pkgName, featureId, 96 uid, /* coarseForTargetSdkLessThanQ */ true, null)) { 97 throw new SecurityException( 98 "UID " + uid + " does not have Coarse/Fine Location permission"); 99 } 100 } 101 102 /** 103 * Checks whether than the target SDK of the package is less than the specified version code. 104 */ isTargetSdkLessThan(String packageName, int versionCode, int callingUid)105 public boolean isTargetSdkLessThan(String packageName, int versionCode, int callingUid) { 106 long ident = Binder.clearCallingIdentity(); 107 try { 108 final int targetSdkVersion; 109 if (SdkLevel.isAtLeastS()) { 110 // >= S, use the lightweight API to just get the target SDK version. 111 Context userContext = createPackageContextAsUser(callingUid); 112 if (userContext == null) return false; 113 targetSdkVersion = userContext.getPackageManager().getTargetSdkVersion(packageName); 114 } else { 115 // < S, use the heavyweight API to get all package info. 116 targetSdkVersion = mContext.getPackageManager().getApplicationInfoAsUser( 117 packageName, 0, 118 UserHandle.getUserHandleForUid(callingUid)).targetSdkVersion; 119 } 120 return targetSdkVersion < versionCode; 121 } catch (PackageManager.NameNotFoundException e) { 122 // In case of exception, assume unknown app (more strict checking) 123 // Note: This case will never happen since checkPackage is 124 // called to verify validity before checking App's version. 125 return false; 126 } finally { 127 Binder.restoreCallingIdentity(ident); 128 } 129 } 130 131 /** 132 * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION or 133 * android.Manifest.permission.ACCESS_FINE_LOCATION (depending on config/targetSDK leve) 134 * and a corresponding app op is allowed for this package and uid. 135 * 136 * @param pkgName PackageName of the application requesting access 137 * @param featureId The feature in the package 138 * @param uid The uid of the package 139 * @param coarseForTargetSdkLessThanQ If true and the targetSDK < Q then will check for COARSE 140 * else (false or targetSDK >= Q) then will check for FINE 141 * @param message A message describing why the permission was checked. Only needed if this is 142 * not inside of a two-way binder call from the data receiver 143 */ checkCallersLocationPermission(String pkgName, @Nullable String featureId, int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message)144 public boolean checkCallersLocationPermission(String pkgName, @Nullable String featureId, 145 int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message) { 146 boolean isTargetSdkLessThanQ = isTargetSdkLessThan(pkgName, Build.VERSION_CODES.Q, uid); 147 148 String permissionType = Manifest.permission.ACCESS_FINE_LOCATION; 149 if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) { 150 // Having FINE permission implies having COARSE permission (but not the reverse) 151 permissionType = Manifest.permission.ACCESS_COARSE_LOCATION; 152 } 153 if (mWifiPermissionsWrapper.getUidPermission(permissionType, uid) 154 == PackageManager.PERMISSION_DENIED) { 155 if (mVerboseLoggingEnabled) { 156 Log.v(TAG, "checkCallersLocationPermission(" + pkgName + "): uid " + uid 157 + " doesn't have permission " + permissionType); 158 } 159 return false; 160 } 161 162 // Always checking FINE - even if will not enforce. This will record the request for FINE 163 // so that a location request by the app is surfaced to the user. 164 boolean isFineLocationAllowed = noteAppOpAllowed( 165 AppOpsManager.OPSTR_FINE_LOCATION, pkgName, featureId, uid, message); 166 if (isFineLocationAllowed) { 167 if (mVerboseLoggingEnabled) { 168 Log.v(TAG, "checkCallersLocationPermission(" + pkgName + "): ok because uid " + uid 169 + " has app-op " + AppOpsManager.OPSTR_FINE_LOCATION); 170 } 171 return true; 172 } 173 if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) { 174 boolean allowed = noteAppOpAllowed(AppOpsManager.OPSTR_COARSE_LOCATION, pkgName, 175 featureId, uid, message); 176 if (mVerboseLoggingEnabled) { 177 Log.v(TAG, "checkCallersLocationPermission(" + pkgName + "): returning " + allowed 178 + " because uid " + uid + (allowed ? "has" : "doesn't have") + " app-op " 179 + AppOpsManager.OPSTR_COARSE_LOCATION); 180 } 181 return allowed; 182 } 183 if (mVerboseLoggingEnabled) { 184 Log.v(TAG, "checkCallersLocationPermission(" + pkgName + "): returning false for " + uid 185 + ": coarseForTargetSdkLessThanQ=" + coarseForTargetSdkLessThanQ 186 + ", isTargetSdkLessThanQ=" + isTargetSdkLessThanQ); 187 188 } 189 return false; 190 } 191 192 /** 193 * Check and enforce Fine Location permission. 194 * 195 * @param pkgName PackageName of the application requesting access 196 * @param featureId The feature in the package 197 * @param uid The uid of the package 198 */ enforceFineLocationPermission(String pkgName, @Nullable String featureId, int uid)199 public void enforceFineLocationPermission(String pkgName, @Nullable String featureId, 200 int uid) { 201 if (!checkCallersFineLocationPermission(pkgName, featureId, uid, false)) { 202 throw new SecurityException("UID " + uid + " does not have Fine Location permission"); 203 } 204 } 205 206 /** 207 * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION 208 * and a corresponding app op is allowed for this package and uid. 209 * 210 * @param pkgName PackageName of the application requesting access 211 * @param featureId The feature in the package 212 * @param uid The uid of the package 213 * @param hideFromAppOps True to invoke {@link AppOpsManager#checkOp(int, int, String)}, false 214 * to invoke {@link AppOpsManager#noteOp(String, int, String, String, 215 * String)}. 216 */ checkCallersFineLocationPermission(String pkgName, @Nullable String featureId, int uid, boolean hideFromAppOps)217 private boolean checkCallersFineLocationPermission(String pkgName, @Nullable String featureId, 218 int uid, boolean hideFromAppOps) { 219 // Having FINE permission implies having COARSE permission (but not the reverse) 220 if (mWifiPermissionsWrapper.getUidPermission( 221 Manifest.permission.ACCESS_FINE_LOCATION, uid) 222 == PackageManager.PERMISSION_DENIED) { 223 return false; 224 } 225 if (hideFromAppOps) { 226 // Don't note the operation, just check if the app is allowed to perform the operation. 227 return checkAppOpAllowed(AppOpsManager.OPSTR_FINE_LOCATION, pkgName, uid); 228 } else { 229 return noteAppOpAllowed(AppOpsManager.OPSTR_FINE_LOCATION, pkgName, featureId, uid, 230 null); 231 } 232 } 233 234 /** 235 * Checks that calling process has android.Manifest.permission.LOCATION_HARDWARE. 236 * 237 * @param uid The uid of the package 238 */ checkCallersHardwareLocationPermission(int uid)239 public boolean checkCallersHardwareLocationPermission(int uid) { 240 return mWifiPermissionsWrapper.getUidPermission(Manifest.permission.LOCATION_HARDWARE, uid) 241 == PackageManager.PERMISSION_GRANTED; 242 } 243 244 /** 245 * API to determine if the caller has permissions to get scan results. Throws SecurityException 246 * if the caller has no permission. 247 * @param pkgName package name of the application requesting access 248 * @param featureId The feature in the package 249 * @param uid The uid of the package 250 * @param message A message describing why the permission was checked. Only needed if this is 251 * not inside of a two-way binder call from the data receiver 252 */ enforceCanAccessScanResults(String pkgName, @Nullable String featureId, int uid, @Nullable String message)253 public void enforceCanAccessScanResults(String pkgName, @Nullable String featureId, int uid, 254 @Nullable String message) 255 throws SecurityException { 256 checkPackage(uid, pkgName); 257 258 // Apps with NETWORK_SETTINGS, NETWORK_SETUP_WIZARD, NETWORK_MANAGED_PROVISIONING, 259 // NETWORK_STACK & MAINLINE_NETWORK_STACK, RADIO_SCAN_WITHOUT_LOCATION are granted a bypass. 260 if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid) 261 || checkNetworkManagedProvisioningPermission(uid) 262 || checkNetworkStackPermission(uid) || checkMainlineNetworkStackPermission(uid) 263 || checkScanWithoutLocationPermission(uid)) { 264 return; 265 } 266 267 // Location mode must be enabled 268 if (!isLocationModeEnabled()) { 269 if (mVerboseLoggingEnabled) { 270 Log.v(TAG, "enforceCanAccessScanResults(pkg=" + pkgName + ", uid=" + uid + "): " 271 + "location is disabled"); 272 } 273 // Location mode is disabled, scan results cannot be returned 274 throw new SecurityException("Location mode is disabled for the device"); 275 } 276 277 // Check if the calling Uid has CAN_READ_PEER_MAC_ADDRESS permission. 278 boolean canCallingUidAccessLocation = checkCallerHasPeersMacAddressPermission(uid); 279 // LocationAccess by App: caller must have Coarse/Fine Location permission to have access to 280 // location information. 281 boolean canAppPackageUseLocation = checkCallersLocationPermission(pkgName, featureId, 282 uid, /* coarseForTargetSdkLessThanQ */ true, message); 283 284 // If neither caller or app has location access, there is no need to check 285 // any other permissions. Deny access to scan results. 286 if (!canCallingUidAccessLocation && !canAppPackageUseLocation) { 287 if (mVerboseLoggingEnabled) { 288 Log.v(TAG, "enforceCanAccessScanResults(pkg=" + pkgName + ", uid=" + uid + "): " 289 + "canCallingUidAccessLocation=" + canCallingUidAccessLocation 290 + ", canAppPackageUseLocation=" + canAppPackageUseLocation); 291 } 292 throw new SecurityException("UID " + uid + " has no location permission"); 293 } 294 // Check if Wifi Scan request is an operation allowed for this App. 295 if (!isScanAllowedbyApps(pkgName, featureId, uid)) { 296 if (mVerboseLoggingEnabled) { 297 Log.v(TAG, "enforceCanAccessScanResults(pkg=" + pkgName + ", uid=" + uid + "): " 298 + "doesn't have app-op " + AppOpsManager.OPSTR_WIFI_SCAN); 299 } 300 throw new SecurityException("UID " + uid + " has no wifi scan permission"); 301 } 302 // If the User or profile is current, permission is granted 303 // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission. 304 boolean isCurrentProfile = isCurrentProfile(uid); 305 if (!isCurrentProfile && !checkInteractAcrossUsersFull(uid)) { 306 if (mVerboseLoggingEnabled) { 307 Log.v(TAG, "enforceCanAccessScanResults(pkg=" + pkgName + ", uid=" + uid + "): " 308 + "isCurrentProfile=" + isCurrentProfile 309 + ", checkInteractAcrossUsersFull=" + checkInteractAcrossUsersFull(uid)); 310 } 311 throw new SecurityException("UID " + uid + " profile not permitted"); 312 } 313 } 314 315 /** 316 * API to determine if the caller has permissions to get scan results. Throws SecurityException 317 * if the caller has no permission. 318 * @param pkgName package name of the application requesting access 319 * @param featureId The feature in the package 320 * @param uid The uid of the package 321 * @param ignoreLocationSettings Whether this request can bypass location settings. 322 * @param hideFromAppOps Whether to note the request in app-ops logging or not. 323 * 324 * Note: This is to be used for checking permissions in the internal WifiScanner API surface 325 * for requests coming from system apps. 326 */ enforceCanAccessScanResultsForWifiScanner(String pkgName, @Nullable String featureId, int uid, boolean ignoreLocationSettings, boolean hideFromAppOps)327 public void enforceCanAccessScanResultsForWifiScanner(String pkgName, 328 @Nullable String featureId, int uid, boolean ignoreLocationSettings, 329 boolean hideFromAppOps) throws SecurityException { 330 checkPackage(uid, pkgName); 331 332 // Location mode must be enabled 333 if (!isLocationModeEnabled()) { 334 if (ignoreLocationSettings) { 335 mLog.w("Request from " + pkgName + " violated location settings"); 336 } else { 337 // Location mode is disabled, scan results cannot be returned 338 throw new SecurityException("Location mode is disabled for the device"); 339 } 340 } 341 // LocationAccess by App: caller must have fine & hardware Location permission to have 342 // access to location information. 343 if (!checkCallersFineLocationPermission(pkgName, featureId, uid, hideFromAppOps) 344 || !checkCallersHardwareLocationPermission(uid)) { 345 throw new SecurityException("UID " + uid + " has no location permission"); 346 } 347 // Check if Wifi Scan request is an operation allowed for this App. 348 if (!isScanAllowedbyApps(pkgName, featureId, uid)) { 349 throw new SecurityException("UID " + uid + " has no wifi scan permission"); 350 } 351 } 352 353 /** 354 * 355 * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION 356 * and a corresponding app op is allowed for this package and uid 357 * 358 * @param pkgName package name of the application requesting access 359 * @param featureId The feature in the package 360 * @param uid The uid of the package 361 * @param needLocationModeEnabled indicates location mode must be enabled. 362 * 363 * @return true if caller has permission, false otherwise 364 */ checkCanAccessWifiDirect(String pkgName, @Nullable String featureId, int uid, boolean needLocationModeEnabled)365 public boolean checkCanAccessWifiDirect(String pkgName, @Nullable String featureId, int uid, 366 boolean needLocationModeEnabled) { 367 try { 368 checkPackage(uid, pkgName); 369 } catch (SecurityException se) { 370 Log.e(TAG, "Package check exception - " + se); 371 return false; 372 } 373 374 // Apps with NETWORK_SETTINGS are granted a bypass. 375 if (checkNetworkSettingsPermission(uid)) { 376 return true; 377 } 378 379 // Location mode must be enabled if needed. 380 if (needLocationModeEnabled && !isLocationModeEnabled()) { 381 Log.e(TAG, "Location mode is disabled for the device"); 382 return false; 383 } 384 385 // LocationAccess by App: caller must have Fine Location permission to have access to 386 // location information. 387 if (!checkCallersLocationPermission(pkgName, featureId, uid, 388 /* coarseForTargetSdkLessThanQ */ false, null)) { 389 Log.e(TAG, "UID " + uid + " has no location permission"); 390 return false; 391 } 392 return true; 393 } 394 395 /** 396 * API to validate if a package name belongs to a UID. Throws SecurityException 397 * if pkgName does not belongs to a UID 398 * 399 * @param pkgName package name of the application requesting access 400 * @param uid The uid of the package 401 * 402 */ checkPackage(int uid, String pkgName)403 public void checkPackage(int uid, String pkgName) throws SecurityException { 404 if (pkgName == null) { 405 throw new SecurityException("Checking UID " + uid + " but Package Name is Null"); 406 } 407 mAppOps.checkPackage(uid, pkgName); 408 } 409 410 /** 411 * Returns true if the caller holds PEERS_MAC_ADDRESS permission. 412 */ checkCallerHasPeersMacAddressPermission(int uid)413 private boolean checkCallerHasPeersMacAddressPermission(int uid) { 414 return mWifiPermissionsWrapper.getUidPermission( 415 android.Manifest.permission.PEERS_MAC_ADDRESS, uid) 416 == PackageManager.PERMISSION_GRANTED; 417 } 418 419 /** 420 * Returns true if Wifi scan operation is allowed for this caller 421 * and package. 422 */ isScanAllowedbyApps(String pkgName, @Nullable String featureId, int uid)423 private boolean isScanAllowedbyApps(String pkgName, @Nullable String featureId, int uid) { 424 return noteAppOpAllowed(AppOpsManager.OPSTR_WIFI_SCAN, pkgName, featureId, uid, null); 425 } 426 427 /** 428 * Returns true if the caller holds INTERACT_ACROSS_USERS_FULL. 429 */ checkInteractAcrossUsersFull(int uid)430 private boolean checkInteractAcrossUsersFull(int uid) { 431 return mWifiPermissionsWrapper.getUidPermission( 432 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid) 433 == PackageManager.PERMISSION_GRANTED; 434 } 435 436 /** 437 * Returns true if the calling user is the current one or a profile of the 438 * current user. 439 */ isCurrentProfile(int uid)440 private boolean isCurrentProfile(int uid) { 441 UserHandle currentUser = UserHandle.of(mWifiPermissionsWrapper.getCurrentUser()); 442 UserHandle callingUser = UserHandle.getUserHandleForUid(uid); 443 return currentUser.equals(callingUser) 444 || mUserManager.isSameProfileGroup(currentUser, callingUser); 445 } 446 noteAppOpAllowed(String op, String pkgName, @Nullable String featureId, int uid, @Nullable String message)447 private boolean noteAppOpAllowed(String op, String pkgName, @Nullable String featureId, 448 int uid, @Nullable String message) { 449 return mAppOps.noteOp(op, uid, pkgName, featureId, message) == AppOpsManager.MODE_ALLOWED; 450 } 451 checkAppOpAllowed(String op, String pkgName, int uid)452 private boolean checkAppOpAllowed(String op, String pkgName, int uid) { 453 return mAppOps.unsafeCheckOp(op, uid, pkgName) == AppOpsManager.MODE_ALLOWED; 454 } 455 retrieveLocationManagerIfNecessary()456 private boolean retrieveLocationManagerIfNecessary() { 457 // This is going to be accessed by multiple threads. 458 synchronized (mLock) { 459 if (mLocationManager == null) { 460 mLocationManager = 461 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); 462 } 463 } 464 return mLocationManager != null; 465 } 466 467 /** 468 * Retrieves a handle to LocationManager (if not already done) and check if location is enabled. 469 */ isLocationModeEnabled()470 public boolean isLocationModeEnabled() { 471 if (!retrieveLocationManagerIfNecessary()) return false; 472 try { 473 return mLocationManager.isLocationEnabledForUser(UserHandle.of( 474 mWifiPermissionsWrapper.getCurrentUser())); 475 } catch (Exception e) { 476 Log.e(TAG, "Failure to get location mode via API, falling back to settings", e); 477 return mFrameworkFacade.getIntegerSetting( 478 mContext, Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) 479 == Settings.Secure.LOCATION_MODE_ON; 480 } 481 } 482 483 /** 484 * Returns true if the |uid| holds NETWORK_SETTINGS permission. 485 */ checkNetworkSettingsPermission(int uid)486 public boolean checkNetworkSettingsPermission(int uid) { 487 return mWifiPermissionsWrapper.getUidPermission( 488 android.Manifest.permission.NETWORK_SETTINGS, uid) 489 == PackageManager.PERMISSION_GRANTED; 490 } 491 492 /** 493 * Returns true if the |uid| holds RADIO_SCAN_WITHOUT_LOCATION permission. 494 */ checkScanWithoutLocationPermission(int uid)495 public boolean checkScanWithoutLocationPermission(int uid) { 496 return mWifiPermissionsWrapper.getUidPermission( 497 android.Manifest.permission.RADIO_SCAN_WITHOUT_LOCATION, uid) 498 == PackageManager.PERMISSION_GRANTED; 499 } 500 501 /** 502 * Returns true if the |uid| holds LOCAL_MAC_ADDRESS permission. 503 */ checkLocalMacAddressPermission(int uid)504 public boolean checkLocalMacAddressPermission(int uid) { 505 return mWifiPermissionsWrapper.getUidPermission( 506 android.Manifest.permission.LOCAL_MAC_ADDRESS, uid) 507 == PackageManager.PERMISSION_GRANTED; 508 } 509 510 /** 511 * Returns true if the |uid| holds NETWORK_SETUP_WIZARD permission. 512 */ checkNetworkSetupWizardPermission(int uid)513 public boolean checkNetworkSetupWizardPermission(int uid) { 514 return mWifiPermissionsWrapper.getUidPermission( 515 android.Manifest.permission.NETWORK_SETUP_WIZARD, uid) 516 == PackageManager.PERMISSION_GRANTED; 517 } 518 519 /** 520 * Returns true if the |uid| holds NETWORK_STACK permission. 521 */ checkNetworkStackPermission(int uid)522 public boolean checkNetworkStackPermission(int uid) { 523 return mWifiPermissionsWrapper.getUidPermission( 524 android.Manifest.permission.NETWORK_STACK, uid) 525 == PackageManager.PERMISSION_GRANTED; 526 } 527 528 /** 529 * Returns true if the |uid| holds MAINLINE_NETWORK_STACK permission. 530 */ checkMainlineNetworkStackPermission(int uid)531 public boolean checkMainlineNetworkStackPermission(int uid) { 532 return mWifiPermissionsWrapper.getUidPermission( 533 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, uid) 534 == PackageManager.PERMISSION_GRANTED; 535 } 536 537 /** 538 * Returns true if the |uid| holds NETWORK_MANAGED_PROVISIONING permission. 539 */ checkNetworkManagedProvisioningPermission(int uid)540 public boolean checkNetworkManagedProvisioningPermission(int uid) { 541 return mWifiPermissionsWrapper.getUidPermission( 542 android.Manifest.permission.NETWORK_MANAGED_PROVISIONING, uid) 543 == PackageManager.PERMISSION_GRANTED; 544 } 545 546 /** 547 * Returns true if the |uid| holds NETWORK_CARRIER_PROVISIONING permission. 548 */ checkNetworkCarrierProvisioningPermission(int uid)549 public boolean checkNetworkCarrierProvisioningPermission(int uid) { 550 return mWifiPermissionsWrapper.getUidPermission( 551 android.Manifest.permission.NETWORK_CARRIER_PROVISIONING, uid) 552 == PackageManager.PERMISSION_GRANTED; 553 } 554 555 /** 556 * Returns true if the |uid| holds READ_WIFI_CREDENTIAL permission. 557 */ checkReadWifiCredentialPermission(int uid)558 public boolean checkReadWifiCredentialPermission(int uid) { 559 return mWifiPermissionsWrapper.getUidPermission( 560 android.Manifest.permission.READ_WIFI_CREDENTIAL, uid) 561 == PackageManager.PERMISSION_GRANTED; 562 } 563 564 /** 565 * Returns true if the |callingUid|/\callingPackage| holds SYSTEM_ALERT_WINDOW permission. 566 */ checkSystemAlertWindowPermission(int callingUid, String callingPackage)567 public boolean checkSystemAlertWindowPermission(int callingUid, String callingPackage) { 568 final int mode = mAppOps.noteOp(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW, callingUid, 569 callingPackage, null, null); 570 if (mode == AppOpsManager.MODE_DEFAULT) { 571 return mWifiPermissionsWrapper.getUidPermission( 572 Manifest.permission.SYSTEM_ALERT_WINDOW, callingUid) 573 == PackageManager.PERMISSION_GRANTED; 574 } 575 return mode == AppOpsManager.MODE_ALLOWED; 576 } 577 retrieveDevicePolicyManagerFromContext(Context context)578 private static DevicePolicyManager retrieveDevicePolicyManagerFromContext(Context context) { 579 DevicePolicyManager devicePolicyManager = 580 context.getSystemService(DevicePolicyManager.class); 581 if (devicePolicyManager == null 582 && context.getPackageManager().hasSystemFeature( 583 PackageManager.FEATURE_DEVICE_ADMIN)) { 584 Log.w(TAG, "Error retrieving DPM service"); 585 } 586 return devicePolicyManager; 587 } 588 589 @Nullable createPackageContextAsUser(int uid)590 private Context createPackageContextAsUser(int uid) { 591 Context userContext = null; 592 try { 593 userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0, 594 UserHandle.getUserHandleForUid(uid)); 595 } catch (PackageManager.NameNotFoundException e) { 596 Log.e(TAG, "Unknown package name"); 597 return null; 598 } 599 if (userContext == null) { 600 Log.e(TAG, "Unable to retrieve user context for " + uid); 601 return null; 602 } 603 return userContext; 604 } 605 retrieveDevicePolicyManagerFromUserContext(int uid)606 private DevicePolicyManager retrieveDevicePolicyManagerFromUserContext(int uid) { 607 Context userContext = createPackageContextAsUser(uid); 608 if (userContext == null) return null; 609 return retrieveDevicePolicyManagerFromContext(userContext); 610 } 611 612 @Nullable getDeviceOwner()613 private Pair<UserHandle, ComponentName> getDeviceOwner() { 614 DevicePolicyManager devicePolicyManager = 615 retrieveDevicePolicyManagerFromContext(mContext); 616 if (devicePolicyManager == null) return null; 617 long ident = Binder.clearCallingIdentity(); 618 UserHandle deviceOwnerUser = null; 619 ComponentName deviceOwnerComponent = null; 620 try { 621 deviceOwnerUser = devicePolicyManager.getDeviceOwnerUser(); 622 deviceOwnerComponent = devicePolicyManager.getDeviceOwnerComponentOnAnyUser(); 623 } finally { 624 Binder.restoreCallingIdentity(ident); 625 } 626 if (deviceOwnerUser == null || deviceOwnerComponent == null) return null; 627 628 if (deviceOwnerComponent.getPackageName() == null) { 629 // shouldn't happen 630 Log.wtf(TAG, "no package name on device owner component: " + deviceOwnerComponent); 631 return null; 632 } 633 return new Pair<>(deviceOwnerUser, deviceOwnerComponent); 634 } 635 636 /** 637 * Returns {@code true} if the calling {@code uid} and {@code packageName} is the device owner. 638 */ isDeviceOwner(int uid, @Nullable String packageName)639 public boolean isDeviceOwner(int uid, @Nullable String packageName) { 640 // Cannot determine if the app is DO/PO if packageName is null. So, will return false to be 641 // safe. 642 if (packageName == null) { 643 Log.e(TAG, "isDeviceOwner: packageName is null, returning false"); 644 return false; 645 } 646 Pair<UserHandle, ComponentName> deviceOwner = getDeviceOwner(); 647 if (mVerboseLoggingEnabled) Log.v(TAG, "deviceOwner:" + deviceOwner); 648 649 // no device owner 650 if (deviceOwner == null) return false; 651 652 return deviceOwner.first.equals(UserHandle.getUserHandleForUid(uid)) 653 && deviceOwner.second.getPackageName().equals(packageName); 654 } 655 656 /** 657 * Returns {@code true} if the calling {@code uid} is the device owner. 658 */ isDeviceOwner(int uid)659 public boolean isDeviceOwner(int uid) { 660 Pair<UserHandle, ComponentName> deviceOwner = getDeviceOwner(); 661 662 // no device owner 663 if (deviceOwner == null) return false; 664 665 // device owner belowngs to wrong user 666 if (!deviceOwner.first.equals(UserHandle.getUserHandleForUid(uid))) return false; 667 668 // finally, check uid 669 String deviceOwnerPackageName = deviceOwner.second.getPackageName(); 670 String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); 671 if (mVerboseLoggingEnabled) { 672 Log.v(TAG, "Packages for uid " + uid + ":" + Arrays.toString(packageNames)); 673 } 674 if (packageNames == null) { 675 Log.w(TAG, "isDeviceOwner(): could not find packages for packageName=" 676 + deviceOwnerPackageName + " uid=" + uid); 677 return false; 678 } 679 for (String packageName : packageNames) { 680 if (deviceOwnerPackageName.equals(packageName)) return true; 681 } 682 683 return false; 684 } 685 686 /** 687 * Returns true if the |callingUid|/\callingPackage| is the profile owner. 688 */ isProfileOwner(int uid, @Nullable String packageName)689 public boolean isProfileOwner(int uid, @Nullable String packageName) { 690 // Cannot determine if the app is DO/PO if packageName is null. So, will return false to be 691 // safe. 692 if (packageName == null) { 693 Log.e(TAG, "isProfileOwner: packageName is null, returning false"); 694 return false; 695 } 696 DevicePolicyManager devicePolicyManager = 697 retrieveDevicePolicyManagerFromUserContext(uid); 698 if (devicePolicyManager == null) return false; 699 return devicePolicyManager.isProfileOwnerApp(packageName); 700 } 701 702 /** Helper method to check if the entity initiating the binder call is a system app. */ isSystem(String packageName, int uid)703 public boolean isSystem(String packageName, int uid) { 704 long ident = Binder.clearCallingIdentity(); 705 try { 706 ApplicationInfo info = mContext.getPackageManager().getApplicationInfoAsUser( 707 packageName, 0, UserHandle.getUserHandleForUid(uid)); 708 return (info.flags & APP_INFO_FLAGS_SYSTEM_APP) != 0; 709 } catch (PackageManager.NameNotFoundException e) { 710 // In case of exception, assume unknown app (more strict checking) 711 // Note: This case will never happen since checkPackage is 712 // called to verify validity before checking App's version. 713 } finally { 714 Binder.restoreCallingIdentity(ident); 715 } 716 return false; 717 } 718 719 /** 720 * Checks if the given UID belongs to the current foreground or device owner user. This is 721 * used to prevent apps running in background users from modifying network 722 * configurations. 723 * <p> 724 * UIDs belonging to system internals (such as SystemUI) are always allowed, 725 * since they always run as {@link UserHandle#USER_SYSTEM}. 726 * 727 * @param uid uid of the app. 728 * @return true if the given UID belongs to the current foreground user, 729 * otherwise false. 730 */ doesUidBelongToCurrentUser(int uid)731 public boolean doesUidBelongToCurrentUser(int uid) { 732 if (uid == android.os.Process.SYSTEM_UID 733 // UIDs with the NETWORK_SETTINGS permission are always allowed since they are 734 // acting on behalf of the user. 735 || checkNetworkSettingsPermission(uid)) { 736 return true; 737 } 738 boolean isCurrentProfile = isCurrentProfile(uid); 739 if (!isCurrentProfile) { 740 // Fix for b/174749461 741 EventLog.writeEvent(0x534e4554, "174749461", -1, 742 "Non foreground user trying to modify wifi configuration"); 743 } 744 return isCurrentProfile || isDeviceOwner(uid); 745 } 746 747 /** 748 * Sets the verbose logging level. 749 */ enableVerboseLogging(boolean enabled)750 public void enableVerboseLogging(boolean enabled) { 751 mVerboseLoggingEnabled = enabled; 752 } 753 } 754