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 static android.Manifest.permission.ACCESS_COARSE_LOCATION; 20 import static android.Manifest.permission.ACCESS_FINE_LOCATION; 21 import static android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED; 22 import static android.Manifest.permission.NEARBY_WIFI_DEVICES; 23 import static android.Manifest.permission.RENOUNCE_PERMISSIONS; 24 import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION; 25 import static android.content.pm.PackageManager.GET_PERMISSIONS; 26 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; 27 28 import android.Manifest; 29 import android.annotation.NonNull; 30 import android.annotation.Nullable; 31 import android.app.AppOpsManager; 32 import android.app.admin.DevicePolicyManager; 33 import android.app.admin.WifiSsidPolicy; 34 import android.content.AttributionSource; 35 import android.content.ComponentName; 36 import android.content.Context; 37 import android.content.pm.ApplicationInfo; 38 import android.content.pm.PackageInfo; 39 import android.content.pm.PackageManager; 40 import android.location.LocationManager; 41 import android.net.NetworkStack; 42 import android.net.wifi.SecurityParams; 43 import android.net.wifi.WifiConfiguration; 44 import android.net.wifi.WifiInfo; 45 import android.net.wifi.WifiSsid; 46 import android.os.Binder; 47 import android.os.Build; 48 import android.os.Process; 49 import android.os.UserHandle; 50 import android.os.UserManager; 51 import android.permission.PermissionManager; 52 import android.provider.Settings; 53 import android.util.ArraySet; 54 import android.util.EventLog; 55 import android.util.Log; 56 import android.util.Pair; 57 import android.util.SparseBooleanArray; 58 59 import androidx.annotation.RequiresApi; 60 61 import com.android.internal.annotations.GuardedBy; 62 import com.android.modules.utils.build.SdkLevel; 63 import com.android.server.wifi.FrameworkFacade; 64 import com.android.server.wifi.WifiInjector; 65 import com.android.server.wifi.WifiLog; 66 import com.android.wifi.resources.R; 67 68 import java.util.Arrays; 69 import java.util.Set; 70 71 /** 72 * A wifi permissions utility assessing permissions 73 * for getting scan results by a package. 74 */ 75 public class WifiPermissionsUtil { 76 private static final String TAG = "WifiPermissionsUtil"; 77 78 private static final int APP_INFO_FLAGS_SYSTEM_APP = 79 ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; 80 private final WifiPermissionsWrapper mWifiPermissionsWrapper; 81 private final Context mContext; 82 private final FrameworkFacade mFrameworkFacade; 83 private final AppOpsManager mAppOps; 84 private final UserManager mUserManager; 85 private final PermissionManager mPermissionManager; 86 private final Object mLock = new Object(); 87 @GuardedBy("mLock") 88 private LocationManager mLocationManager; 89 private WifiLog mLog; 90 private boolean mVerboseLoggingEnabled; 91 private final SparseBooleanArray mOemPrivilegedAdminUidCache = new SparseBooleanArray(); 92 WifiPermissionsUtil(WifiPermissionsWrapper wifiPermissionsWrapper, Context context, UserManager userManager, WifiInjector wifiInjector)93 public WifiPermissionsUtil(WifiPermissionsWrapper wifiPermissionsWrapper, 94 Context context, UserManager userManager, WifiInjector wifiInjector) { 95 mWifiPermissionsWrapper = wifiPermissionsWrapper; 96 mContext = context; 97 mFrameworkFacade = wifiInjector.getFrameworkFacade(); 98 mUserManager = userManager; 99 mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 100 mPermissionManager = mContext.getSystemService(PermissionManager.class); 101 mLog = wifiInjector.makeLog(TAG); 102 } 103 104 105 /** 106 * A class to store binder caller information. 107 */ 108 public static final class CallerIdentity { 109 int mUid; 110 int mPid; 111 String mPackageName; 112 String mFeatureId; 113 CallerIdentity(int uid, int pid, String packageName, String featureId)114 public CallerIdentity(int uid, int pid, String packageName, String featureId) { 115 mUid = uid; 116 mPid = pid; 117 mPackageName = packageName; 118 mFeatureId = featureId; 119 } 120 getUid()121 public int getUid() { 122 return mUid; 123 } 124 getPid()125 public int getPid() { 126 return mPid; 127 } 128 getPackageName()129 public String getPackageName() { 130 return mPackageName; 131 } 132 getFeatureId()133 public String getFeatureId() { 134 return mFeatureId; 135 } 136 137 @NonNull 138 @Override toString()139 public String toString() { 140 return "CallerIdentity{" 141 + "Uid= " + mUid 142 + ", Pid= " + mPid 143 + ", PackageName= " + mPackageName 144 + ", FeatureId= " + mFeatureId 145 + '}'; 146 } 147 } 148 149 /** 150 * Checks if the app has the permission to override Wi-Fi network configuration or not. 151 * 152 * @param uid uid of the app. 153 * @return true if the app does have the permission, false otherwise. 154 */ checkConfigOverridePermission(int uid)155 public boolean checkConfigOverridePermission(int uid) { 156 return mWifiPermissionsWrapper.getOverrideWifiConfigPermission(uid) 157 == PackageManager.PERMISSION_GRANTED; 158 } 159 160 /** 161 * Check and enforce Coarse or Fine Location permission (depending on target SDK). 162 * 163 * @param pkgName PackageName of the application requesting access 164 * @param featureId The feature in the package 165 * @param uid The uid of the package 166 */ enforceLocationPermission(String pkgName, @Nullable String featureId, int uid)167 public void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid) { 168 if (!checkCallersLocationPermission(pkgName, featureId, 169 uid, /* coarseForTargetSdkLessThanQ */ true, null)) { 170 throw new SecurityException( 171 "UID " + uid + " does not have Coarse/Fine Location permission"); 172 } 173 } 174 175 /** 176 * Version of enforceNearbyDevicesPermission that do not throw an exception. 177 */ checkNearbyDevicesPermission(AttributionSource attributionSource, boolean checkForLocation, String message)178 public boolean checkNearbyDevicesPermission(AttributionSource attributionSource, 179 boolean checkForLocation, String message) { 180 try { 181 enforceNearbyDevicesPermission(attributionSource, checkForLocation, message); 182 } catch (SecurityException e) { 183 return false; 184 } 185 return true; 186 } 187 188 /** 189 * Check and enforce NEARBY_WIFI_DEVICES permission and optionally enforce for either location 190 * disavowal or location permission. 191 * 192 * Note, this is only callable on SDK version T and later. 193 * 194 * @param attributionSource AttributionSource of the caller. 195 * @param checkForLocation If true will require the caller to either disavow location 196 * or actually have location permission. 197 * @param message String to log as the reason for performing permission checks. 198 */ enforceNearbyDevicesPermission(AttributionSource attributionSource, boolean checkForLocation, String message)199 public void enforceNearbyDevicesPermission(AttributionSource attributionSource, 200 boolean checkForLocation, String message) throws SecurityException { 201 if (!SdkLevel.isAtLeastT()) { 202 Log.wtf(TAG, "enforceNearbyDevicesPermission should never be called on pre-T " 203 + "devices"); 204 throw new SecurityException("enforceNearbyDevicesPermission requires at least " 205 + "Android T"); 206 } 207 if (attributionSource == null) { 208 throw new SecurityException("enforceNearbyDevicesPermission attributionSource is null"); 209 } 210 if (mVerboseLoggingEnabled) { 211 Log.v(TAG, "enforceNearbyDevicesPermission(attributionSource=" 212 + attributionSource + ", checkForLocation=" + checkForLocation); 213 } 214 if (!attributionSource.checkCallingUid()) { 215 throw new SecurityException("enforceNearbyDevicesPermission invalid attribution source=" 216 + attributionSource); 217 } 218 String packageName = attributionSource.getPackageName(); 219 int uid = attributionSource.getUid(); 220 checkPackage(uid, packageName); 221 // Apps with NETWORK_SETTINGS, NETWORK_SETUP_WIZARD, NETWORK_MANAGED_PROVISIONING, 222 // NETWORK_STACK & MAINLINE_NETWORK_STACK, RADIO_SCAN_WITHOUT_LOCATION are granted a bypass. 223 if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid) 224 || checkNetworkManagedProvisioningPermission(uid) 225 || checkNetworkStackPermission(uid) || checkMainlineNetworkStackPermission(uid) 226 || checkScanWithoutLocationPermission(uid)) { 227 return; 228 } 229 230 int permissionCheckResult = mPermissionManager.checkPermissionForDataDelivery( 231 Manifest.permission.NEARBY_WIFI_DEVICES, attributionSource, message); 232 if (permissionCheckResult != PermissionManager.PERMISSION_GRANTED) { 233 throw new SecurityException("package=" + packageName + " UID=" + uid 234 + " does not have nearby devices permission."); 235 } 236 if (mVerboseLoggingEnabled) { 237 Log.v(TAG, "pkg=" + packageName + " has NEARBY_WIFI_DEVICES permission."); 238 } 239 if (!checkForLocation) { 240 // No need to check for location permission. All done now and return. 241 return; 242 } 243 244 // There are 2 ways to disavow location. Skip location permission check if any of the 245 // 2 ways are used to disavow location usage. 246 // First check if the app renounced location. 247 // Check every step along the attribution chain for a renouncement. 248 AttributionSource currentAttrib = attributionSource; 249 while (true) { 250 int curUid = currentAttrib.getUid(); 251 String curPackageName = currentAttrib.getPackageName(); 252 // If location has been renounced anywhere in the chain we treat it as a disavowal. 253 if (currentAttrib.getRenouncedPermissions().contains(ACCESS_FINE_LOCATION) 254 && mWifiPermissionsWrapper.getUidPermission(RENOUNCE_PERMISSIONS, curUid) 255 == PackageManager.PERMISSION_GRANTED) { 256 if (mVerboseLoggingEnabled) { 257 Log.v(TAG, "package=" + curPackageName + " UID=" + curUid 258 + " has renounced location permission - bypassing location check."); 259 } 260 return; 261 } 262 AttributionSource nextAttrib = currentAttrib.getNext(); 263 if (nextAttrib == null) { 264 break; 265 } 266 currentAttrib = nextAttrib; 267 } 268 // If the app did not renounce location, check if "neverForLocation" is set. 269 PackageManager pm = mContext.getPackageManager(); 270 long ident = Binder.clearCallingIdentity(); 271 try { 272 PackageInfo pkgInfo = pm.getPackageInfo(packageName, 273 GET_PERMISSIONS | MATCH_UNINSTALLED_PACKAGES); 274 int requestedPermissionsLength = pkgInfo.requestedPermissions == null 275 || pkgInfo.requestedPermissionsFlags == null ? 0 276 : pkgInfo.requestedPermissions.length; 277 if (requestedPermissionsLength == 0) { 278 Log.e(TAG, "package=" + packageName + " unexpectedly has null " 279 + "requestedPermissions or requestPermissionFlags."); 280 } 281 for (int i = 0; i < requestedPermissionsLength; i++) { 282 if (pkgInfo.requestedPermissions[i].equals(NEARBY_WIFI_DEVICES) 283 && (pkgInfo.requestedPermissionsFlags[i] 284 & PackageInfo.REQUESTED_PERMISSION_NEVER_FOR_LOCATION) != 0) { 285 if (mVerboseLoggingEnabled) { 286 Log.v(TAG, "package=" + packageName + " UID=" + uid 287 + " has declared neverForLocation - bypassing location check."); 288 } 289 return; 290 } 291 } 292 } catch (PackageManager.NameNotFoundException e) { 293 Log.w(TAG, "Could not find package for disavowal check: " + packageName); 294 } finally { 295 Binder.restoreCallingIdentity(ident); 296 } 297 // App did not disavow location. Check for location permission and location mode. 298 ident = Binder.clearCallingIdentity(); 299 try { 300 if (!isLocationModeEnabled()) { 301 if (mVerboseLoggingEnabled) { 302 Log.v(TAG, "enforceNearbyDevicesPermission(pkg=" + packageName + ", uid=" + uid 303 + "): " 304 + "location is disabled"); 305 } 306 throw new SecurityException("Location mode is disabled for the device"); 307 } 308 } finally { 309 Binder.restoreCallingIdentity(ident); 310 } 311 if (mPermissionManager.checkPermissionForDataDelivery( 312 ACCESS_FINE_LOCATION, attributionSource, message) 313 == PermissionManager.PERMISSION_GRANTED) { 314 if (mVerboseLoggingEnabled) { 315 Log.v(TAG, "package=" + packageName + " UID=" + uid + " has location permission."); 316 } 317 return; 318 } 319 throw new SecurityException("package=" + packageName + ", UID=" + uid 320 + " does not have Fine Location permission"); 321 } 322 323 /** 324 * Checks whether than the target SDK of the package is less than the specified version code. 325 */ isTargetSdkLessThan(String packageName, int versionCode, int callingUid)326 public boolean isTargetSdkLessThan(String packageName, int versionCode, int callingUid) { 327 long ident = Binder.clearCallingIdentity(); 328 try { 329 final int targetSdkVersion; 330 if (SdkLevel.isAtLeastS()) { 331 // >= S, use the lightweight API to just get the target SDK version. 332 Context userContext = createPackageContextAsUser(callingUid); 333 if (userContext == null) return false; 334 targetSdkVersion = userContext.getPackageManager().getTargetSdkVersion(packageName); 335 } else { 336 // < S, use the heavyweight API to get all package info. 337 targetSdkVersion = mContext.getPackageManager().getApplicationInfoAsUser( 338 packageName, 0, 339 UserHandle.getUserHandleForUid(callingUid)).targetSdkVersion; 340 } 341 return targetSdkVersion < versionCode; 342 } catch (PackageManager.NameNotFoundException e) { 343 // In case of exception, assume unknown app (more strict checking) 344 // Note: This case will never happen since checkPackage is 345 // called to verify validity before checking App's version. 346 return false; 347 } finally { 348 Binder.restoreCallingIdentity(ident); 349 } 350 } 351 352 /** 353 * Returns the global demo mode of the device. Note that there is a 354 * UserManager.isDeviceInDemoMode(Context) which does the same thing - but is not a 355 * public/system API (whereas the Settings.Global.DEVICE_DEMO_MODE is a System API). 356 */ isDeviceInDemoMode(Context context)357 public boolean isDeviceInDemoMode(Context context) { 358 return Settings.Global.getInt(context.getContentResolver(), 359 Settings.Global.DEVICE_DEMO_MODE, 0) > 0; 360 } 361 362 /** 363 * Check and enforce Location permission in the manifest. 364 * 365 * @param uid uid of the app. 366 * @param isCoarseOnly whether permission type is COARSE or FINE since FINE permission 367 * implies having COARSE permission. 368 */ enforceLocationPermissionInManifest(int uid, boolean isCoarseOnly)369 public void enforceLocationPermissionInManifest(int uid, boolean isCoarseOnly) { 370 if (!checkCallersLocationPermissionInManifest(uid, isCoarseOnly)) { 371 throw new SecurityException("UID " + uid + " does not have Location permission (" 372 + "isCoarseOnly = " + isCoarseOnly + " )"); 373 } 374 } 375 376 /** 377 * Checks if the app has the location permission in the manifest. 378 * 379 * @param uid uid of the app. 380 * @param isCoarseOnly whether permission type is COARSE or FINE since FINE permission 381 * implies having COARSE permission. 382 * @return true if the app does have the permission, false otherwise. 383 */ checkCallersLocationPermissionInManifest(int uid, boolean isCoarseOnly)384 public boolean checkCallersLocationPermissionInManifest(int uid, boolean isCoarseOnly) { 385 // Having FINE permission implies having COARSE permission (but not the reverse) 386 String permissionType = isCoarseOnly ? ACCESS_COARSE_LOCATION : ACCESS_FINE_LOCATION; 387 return mWifiPermissionsWrapper.getUidPermission(permissionType, uid) 388 == PackageManager.PERMISSION_GRANTED; 389 } 390 391 /** 392 * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION or 393 * android.Manifest.permission.ACCESS_FINE_LOCATION (depending on config/targetSDK leve) 394 * and a corresponding app op is allowed for this package and uid. 395 * 396 * @param pkgName PackageName of the application requesting access 397 * @param featureId The feature in the package 398 * @param uid The uid of the package 399 * @param coarseForTargetSdkLessThanQ If true and the targetSDK < Q then will check for COARSE 400 * else (false or targetSDK >= Q) then will check for FINE 401 * @param message A message describing why the permission was checked. Only needed if this is 402 * not inside of a two-way binder call from the data receiver 403 */ checkCallersLocationPermission(String pkgName, @Nullable String featureId, int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message)404 public boolean checkCallersLocationPermission(String pkgName, @Nullable String featureId, 405 int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message) { 406 boolean isTargetSdkLessThanQ = isTargetSdkLessThan(pkgName, Build.VERSION_CODES.Q, uid); 407 408 String permissionType = ACCESS_FINE_LOCATION; 409 if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) { 410 // Having FINE permission implies having COARSE permission (but not the reverse) 411 permissionType = ACCESS_COARSE_LOCATION; 412 } 413 if (mWifiPermissionsWrapper.getUidPermission(permissionType, uid) 414 == PackageManager.PERMISSION_DENIED) { 415 if (mVerboseLoggingEnabled) { 416 Log.v(TAG, "checkCallersLocationPermission(" + pkgName + "): uid " + uid 417 + " doesn't have permission " + permissionType); 418 } 419 return false; 420 } 421 422 // Always checking FINE - even if will not enforce. This will record the request for FINE 423 // so that a location request by the app is surfaced to the user. 424 boolean isFineLocationAllowed = noteAppOpAllowed( 425 AppOpsManager.OPSTR_FINE_LOCATION, pkgName, featureId, uid, message); 426 if (isFineLocationAllowed) { 427 if (mVerboseLoggingEnabled) { 428 Log.v(TAG, "checkCallersLocationPermission(" + pkgName + "): ok because uid " + uid 429 + " has app-op " + AppOpsManager.OPSTR_FINE_LOCATION); 430 } 431 return true; 432 } 433 if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) { 434 boolean allowed = noteAppOpAllowed(AppOpsManager.OPSTR_COARSE_LOCATION, pkgName, 435 featureId, uid, message); 436 if (mVerboseLoggingEnabled) { 437 Log.v(TAG, "checkCallersLocationPermission(" + pkgName + "): returning " + allowed 438 + " because uid " + uid + (allowed ? "has" : "doesn't have") + " app-op " 439 + AppOpsManager.OPSTR_COARSE_LOCATION); 440 } 441 return allowed; 442 } 443 if (mVerboseLoggingEnabled) { 444 Log.v(TAG, "checkCallersLocationPermission(" + pkgName + "): returning false for " + uid 445 + ": coarseForTargetSdkLessThanQ=" + coarseForTargetSdkLessThanQ 446 + ", isTargetSdkLessThanQ=" + isTargetSdkLessThanQ); 447 448 } 449 return false; 450 } 451 452 /** 453 * Check and enforce Fine Location permission. 454 * 455 * @param pkgName PackageName of the application requesting access 456 * @param featureId The feature in the package 457 * @param uid The uid of the package 458 */ enforceFineLocationPermission(String pkgName, @Nullable String featureId, int uid)459 public void enforceFineLocationPermission(String pkgName, @Nullable String featureId, 460 int uid) { 461 if (!checkCallersFineLocationPermission(pkgName, featureId, uid, false, false)) { 462 throw new SecurityException("UID " + uid + " does not have Fine Location permission"); 463 } 464 } 465 466 /** 467 * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION 468 * and a corresponding app op is allowed for this package and uid. 469 * 470 * @param pkgName PackageName of the application requesting access 471 * @param featureId The feature in the package 472 * @param uid The uid of the package 473 * @param hideFromAppOps True to invoke {@link AppOpsManager#checkOp(int, int, String)}, false 474 * to invoke {@link AppOpsManager#noteOp(String, int, String, String, 475 * String)}. 476 * @param ignoreLocationSettings Whether this request can bypass location settings. 477 */ checkCallersFineLocationPermission(String pkgName, @Nullable String featureId, int uid, boolean hideFromAppOps, boolean ignoreLocationSettings)478 private boolean checkCallersFineLocationPermission(String pkgName, @Nullable String featureId, 479 int uid, boolean hideFromAppOps, boolean ignoreLocationSettings) { 480 // Having FINE permission implies having COARSE permission (but not the reverse) 481 if (mWifiPermissionsWrapper.getUidPermission( 482 ACCESS_FINE_LOCATION, uid) 483 == PackageManager.PERMISSION_DENIED) { 484 return false; 485 } 486 487 boolean isAllowed; 488 if (hideFromAppOps) { 489 // Don't note the operation, just check if the app is allowed to perform the operation. 490 isAllowed = checkAppOpAllowed(AppOpsManager.OPSTR_FINE_LOCATION, pkgName, uid); 491 } else { 492 isAllowed = noteAppOpAllowed(AppOpsManager.OPSTR_FINE_LOCATION, pkgName, featureId, uid, 493 null); 494 } 495 // If the ignoreLocationSettings is true, we always return true. This is for the emergency 496 // location service use case. But still notify the operation manager. 497 return isAllowed || ignoreLocationSettings; 498 } 499 500 /** 501 * Check and enforce Coarse Location permission. 502 * 503 * @param pkgName PackageName of the application requesting access. 504 * @param featureId The feature in the package. 505 * @param uid The uid of the package. 506 */ enforceCoarseLocationPermission(String pkgName, @Nullable String featureId, int uid)507 public void enforceCoarseLocationPermission(String pkgName, @Nullable String featureId, 508 int uid) { 509 if (!checkCallersCoarseLocationPermission(pkgName, featureId, 510 uid, null)) { 511 throw new SecurityException( 512 "UID " + uid + " does not have Coarse Location permission"); 513 } 514 } 515 516 /** 517 * Checks that calling process has android.Manifest.permission.ACCESS_COARSE_LOCATION 518 * and a corresponding app op is allowed for this package and uid. 519 * 520 * @param pkgName PackageName of the application requesting access. 521 * @param featureId The feature in the package. 522 * @param uid The uid of the package. 523 * @param message A message describing why the permission was checked. Only needed if this is 524 * not inside of a two-way binder call from the data receiver. 525 */ checkCallersCoarseLocationPermission(String pkgName, @Nullable String featureId, int uid, @Nullable String message)526 public boolean checkCallersCoarseLocationPermission(String pkgName, @Nullable String featureId, 527 int uid, @Nullable String message) { 528 if (mWifiPermissionsWrapper.getUidPermission(ACCESS_COARSE_LOCATION, uid) 529 == PackageManager.PERMISSION_DENIED) { 530 if (mVerboseLoggingEnabled) { 531 Log.v(TAG, "checkCallersCoarseLocationPermission(" + pkgName + "): uid " + uid 532 + " doesn't have ACCESS_COARSE_LOCATION permission "); 533 } 534 return false; 535 } 536 boolean allowed = noteAppOpAllowed(AppOpsManager.OPSTR_COARSE_LOCATION, pkgName, 537 featureId, uid, message); 538 if (mVerboseLoggingEnabled) { 539 Log.v(TAG, "checkCallersCoarseLocationPermission(" + pkgName + "): returning " 540 + allowed + " because uid " + uid + (allowed ? "has" : "doesn't have") 541 + " app-op " + AppOpsManager.OPSTR_COARSE_LOCATION); 542 } 543 return allowed; 544 } 545 546 /** 547 * Checks that calling process has android.Manifest.permission.LOCATION_HARDWARE. 548 * 549 * @param uid The uid of the package 550 */ checkCallersHardwareLocationPermission(int uid)551 public boolean checkCallersHardwareLocationPermission(int uid) { 552 return mWifiPermissionsWrapper.getUidPermission(Manifest.permission.LOCATION_HARDWARE, uid) 553 == PackageManager.PERMISSION_GRANTED; 554 } 555 556 /** 557 * API to determine if the caller has permissions to get scan results. Throws SecurityException 558 * if the caller has no permission. 559 * @param pkgName package name of the application requesting access 560 * @param featureId The feature in the package 561 * @param uid The uid of the package 562 * @param message A message describing why the permission was checked. Only needed if this is 563 * not inside of a two-way binder call from the data receiver 564 */ enforceCanAccessScanResults(String pkgName, @Nullable String featureId, int uid, @Nullable String message)565 public void enforceCanAccessScanResults(String pkgName, @Nullable String featureId, int uid, 566 @Nullable String message) 567 throws SecurityException { 568 checkPackage(uid, pkgName); 569 570 // Apps with NETWORK_SETTINGS, NETWORK_SETUP_WIZARD, NETWORK_MANAGED_PROVISIONING, 571 // NETWORK_STACK & MAINLINE_NETWORK_STACK, RADIO_SCAN_WITHOUT_LOCATION are granted a bypass. 572 if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid) 573 || checkNetworkManagedProvisioningPermission(uid) 574 || checkNetworkStackPermission(uid) || checkMainlineNetworkStackPermission(uid) 575 || checkScanWithoutLocationPermission(uid)) { 576 return; 577 } 578 579 // Location mode must be enabled 580 if (!isLocationModeEnabled()) { 581 if (mVerboseLoggingEnabled) { 582 Log.v(TAG, "enforceCanAccessScanResults(pkg=" + pkgName + ", uid=" + uid + "): " 583 + "location is disabled"); 584 } 585 // Location mode is disabled, scan results cannot be returned 586 throw new SecurityException("Location mode is disabled for the device"); 587 } 588 589 // Check if the calling Uid has CAN_READ_PEER_MAC_ADDRESS permission. 590 boolean canCallingUidAccessLocation = checkCallerHasPeersMacAddressPermission(uid); 591 // LocationAccess by App: caller must have Coarse/Fine Location permission to have access to 592 // location information. 593 boolean canAppPackageUseLocation = checkCallersLocationPermission(pkgName, featureId, 594 uid, /* coarseForTargetSdkLessThanQ */ true, message); 595 596 // If neither caller or app has location access, there is no need to check 597 // any other permissions. Deny access to scan results. 598 if (!canCallingUidAccessLocation && !canAppPackageUseLocation) { 599 if (mVerboseLoggingEnabled) { 600 Log.v(TAG, "enforceCanAccessScanResults(pkg=" + pkgName + ", uid=" + uid + "): " 601 + "canCallingUidAccessLocation=" + canCallingUidAccessLocation 602 + ", canAppPackageUseLocation=" + canAppPackageUseLocation); 603 } 604 throw new SecurityException("UID " + uid + " has no location permission"); 605 } 606 // Check if Wifi Scan request is an operation allowed for this App. 607 if (!isScanAllowedbyApps(pkgName, featureId, uid)) { 608 if (mVerboseLoggingEnabled) { 609 Log.v(TAG, "enforceCanAccessScanResults(pkg=" + pkgName + ", uid=" + uid + "): " 610 + "doesn't have app-op " + AppOpsManager.OPSTR_WIFI_SCAN); 611 } 612 throw new SecurityException("UID " + uid + " has no wifi scan permission"); 613 } 614 // If the User or profile is current, permission is granted 615 // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission. 616 boolean isCurrentProfile = doesUidBelongToUser( 617 uid, mWifiPermissionsWrapper.getCurrentUser()); 618 if (!isCurrentProfile && !checkInteractAcrossUsersFull(uid)) { 619 if (mVerboseLoggingEnabled) { 620 Log.v(TAG, "enforceCanAccessScanResults(pkg=" + pkgName + ", uid=" + uid + "): " 621 + "isCurrentProfile=" + isCurrentProfile 622 + ", checkInteractAcrossUsersFull=" + checkInteractAcrossUsersFull(uid)); 623 } 624 throw new SecurityException("UID " + uid + " profile not permitted"); 625 } 626 } 627 628 /** 629 * API to determine if the caller has permissions to get scan results. Throws SecurityException 630 * if the caller has no permission. 631 * @param pkgName package name of the application requesting access 632 * @param featureId The feature in the package 633 * @param uid The uid of the package 634 * @param ignoreLocationSettings Whether this request can bypass location settings. 635 * @param hideFromAppOps Whether to note the request in app-ops logging or not. 636 * 637 * Note: This is to be used for checking permissions in the internal WifiScanner API surface 638 * for requests coming from system apps. 639 */ enforceCanAccessScanResultsForWifiScanner(String pkgName, @Nullable String featureId, int uid, boolean ignoreLocationSettings, boolean hideFromAppOps)640 public void enforceCanAccessScanResultsForWifiScanner(String pkgName, 641 @Nullable String featureId, int uid, boolean ignoreLocationSettings, 642 boolean hideFromAppOps) throws SecurityException { 643 checkPackage(uid, pkgName); 644 645 // Apps with NETWORK_SETTINGS or NETWORK_SETUP_WIZARD get a bypass 646 if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid)) { 647 return; 648 } 649 650 // Location mode must be enabled 651 if (!isLocationModeEnabled()) { 652 if (ignoreLocationSettings) { 653 mLog.w("Request from " + pkgName + " violated location settings"); 654 } else { 655 // Location mode is disabled, scan results cannot be returned 656 throw new SecurityException("Location mode is disabled for the device"); 657 } 658 } 659 // LocationAccess by App: caller must have fine & hardware Location permission to have 660 // access to location information. 661 if (!checkCallersFineLocationPermission(pkgName, featureId, uid, hideFromAppOps, 662 ignoreLocationSettings) || !checkCallersHardwareLocationPermission(uid)) { 663 throw new SecurityException("UID " + uid + " has no location permission"); 664 } 665 // Check if Wifi Scan request is an operation allowed for this App. 666 if (!isScanAllowedbyApps(pkgName, featureId, uid)) { 667 throw new SecurityException("UID " + uid + " has no wifi scan permission"); 668 } 669 } 670 671 /** 672 * 673 * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION 674 * and a corresponding app op is allowed for this package and uid 675 * 676 * @param pkgName package name of the application requesting access 677 * @param featureId The feature in the package 678 * @param uid The uid of the package 679 * @param needLocationModeEnabled indicates location mode must be enabled. 680 * 681 * @return true if caller has permission, false otherwise 682 */ checkCanAccessWifiDirect(String pkgName, @Nullable String featureId, int uid, boolean needLocationModeEnabled)683 public boolean checkCanAccessWifiDirect(String pkgName, @Nullable String featureId, int uid, 684 boolean needLocationModeEnabled) { 685 try { 686 checkPackage(uid, pkgName); 687 } catch (SecurityException se) { 688 Log.e(TAG, "Package check exception - " + se); 689 return false; 690 } 691 692 // Apps with NETWORK_SETTINGS are granted a bypass. 693 if (checkNetworkSettingsPermission(uid)) { 694 return true; 695 } 696 697 // Location mode must be enabled if needed. 698 if (needLocationModeEnabled && !isLocationModeEnabled()) { 699 Log.e(TAG, "Location mode is disabled for the device"); 700 return false; 701 } 702 703 // LocationAccess by App: caller must have Fine Location permission to have access to 704 // location information. 705 if (!checkCallersLocationPermission(pkgName, featureId, uid, 706 /* coarseForTargetSdkLessThanQ */ false, null)) { 707 Log.e(TAG, "UID " + uid + " has no location permission"); 708 return false; 709 } 710 return true; 711 } 712 713 /** 714 * API to validate if a package name belongs to a UID. Throws SecurityException 715 * if pkgName does not belongs to a UID 716 * 717 * @param pkgName package name of the application requesting access 718 * @param uid The uid of the package 719 * 720 */ checkPackage(int uid, String pkgName)721 public void checkPackage(int uid, String pkgName) throws SecurityException { 722 if (pkgName == null) { 723 throw new SecurityException("Checking UID " + uid + " but Package Name is Null"); 724 } 725 mAppOps.checkPackage(uid, pkgName); 726 } 727 728 /** 729 * Returns true if the caller holds PEERS_MAC_ADDRESS permission. 730 */ checkCallerHasPeersMacAddressPermission(int uid)731 private boolean checkCallerHasPeersMacAddressPermission(int uid) { 732 return mWifiPermissionsWrapper.getUidPermission( 733 android.Manifest.permission.PEERS_MAC_ADDRESS, uid) 734 == PackageManager.PERMISSION_GRANTED; 735 } 736 737 /** 738 * Returns true if Wifi scan operation is allowed for this caller 739 * and package. 740 */ isScanAllowedbyApps(String pkgName, @Nullable String featureId, int uid)741 private boolean isScanAllowedbyApps(String pkgName, @Nullable String featureId, int uid) { 742 return noteAppOpAllowed(AppOpsManager.OPSTR_WIFI_SCAN, pkgName, featureId, uid, null); 743 } 744 745 /** 746 * Returns true if the caller holds INTERACT_ACROSS_USERS_FULL. 747 */ checkInteractAcrossUsersFull(int uid)748 private boolean checkInteractAcrossUsersFull(int uid) { 749 return mWifiPermissionsWrapper.getUidPermission( 750 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid) 751 == PackageManager.PERMISSION_GRANTED; 752 } 753 noteAppOpAllowed(String op, String pkgName, @Nullable String featureId, int uid, @Nullable String message)754 private boolean noteAppOpAllowed(String op, String pkgName, @Nullable String featureId, 755 int uid, @Nullable String message) { 756 return mAppOps.noteOp(op, uid, pkgName, featureId, message) == AppOpsManager.MODE_ALLOWED; 757 } 758 checkAppOpAllowed(String op, String pkgName, int uid)759 private boolean checkAppOpAllowed(String op, String pkgName, int uid) { 760 return mAppOps.unsafeCheckOp(op, uid, pkgName) == AppOpsManager.MODE_ALLOWED; 761 } 762 retrieveLocationManagerIfNecessary()763 private boolean retrieveLocationManagerIfNecessary() { 764 // This is going to be accessed by multiple threads. 765 synchronized (mLock) { 766 if (mLocationManager == null) { 767 mLocationManager = 768 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); 769 } 770 } 771 return mLocationManager != null; 772 } 773 774 /** 775 * Retrieves a handle to LocationManager (if not already done) and check if location is enabled. 776 */ isLocationModeEnabled()777 public boolean isLocationModeEnabled() { 778 if (!retrieveLocationManagerIfNecessary()) return false; 779 try { 780 return mLocationManager.isLocationEnabledForUser(UserHandle.of( 781 mWifiPermissionsWrapper.getCurrentUser())); 782 } catch (Exception e) { 783 Log.e(TAG, "Failure to get location mode via API, falling back to settings", e); 784 return mFrameworkFacade.getIntegerSetting( 785 mContext, Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) 786 == Settings.Secure.LOCATION_MODE_ON; 787 } 788 } 789 790 /** 791 * Returns true if the |uid| holds REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION permission. 792 */ checkRequestCompanionProfileAutomotiveProjectionPermission(int uid)793 public boolean checkRequestCompanionProfileAutomotiveProjectionPermission(int uid) { 794 return mWifiPermissionsWrapper.getUidPermission( 795 REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION, uid) 796 == PackageManager.PERMISSION_GRANTED; 797 } 798 799 /** 800 * Returns true if the |uid| holds ENTER_CAR_MODE_PRIORITIZED permission. 801 */ checkEnterCarModePrioritized(int uid)802 public boolean checkEnterCarModePrioritized(int uid) { 803 return mWifiPermissionsWrapper.getUidPermission(ENTER_CAR_MODE_PRIORITIZED, uid) 804 == PackageManager.PERMISSION_GRANTED; 805 } 806 807 /** 808 * Returns true if the |uid| holds MANAGE_WIFI_INTERFACES permission. 809 */ checkManageWifiInterfacesPermission(int uid)810 public boolean checkManageWifiInterfacesPermission(int uid) { 811 return mWifiPermissionsWrapper.getUidPermission( 812 android.Manifest.permission.MANAGE_WIFI_INTERFACES, uid) 813 == PackageManager.PERMISSION_GRANTED; 814 } 815 816 /** 817 * Returns true if the |uid| holds MANAGE_WIFI_NETWORK_SELECTION permission. 818 */ checkManageWifiNetworkSelectionPermission(int uid)819 public boolean checkManageWifiNetworkSelectionPermission(int uid) { 820 return mWifiPermissionsWrapper.getUidPermission( 821 android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION, uid) 822 == PackageManager.PERMISSION_GRANTED; 823 } 824 825 /** 826 * Returns true if the |uid| holds NETWORK_SETTINGS permission. 827 */ checkNetworkSettingsPermission(int uid)828 public boolean checkNetworkSettingsPermission(int uid) { 829 return mWifiPermissionsWrapper.getUidPermission( 830 android.Manifest.permission.NETWORK_SETTINGS, uid) 831 == PackageManager.PERMISSION_GRANTED; 832 } 833 834 /** 835 * Returns true if the |uid| holds RADIO_SCAN_WITHOUT_LOCATION permission. 836 */ checkScanWithoutLocationPermission(int uid)837 public boolean checkScanWithoutLocationPermission(int uid) { 838 return mWifiPermissionsWrapper.getUidPermission( 839 android.Manifest.permission.RADIO_SCAN_WITHOUT_LOCATION, uid) 840 == PackageManager.PERMISSION_GRANTED; 841 } 842 843 /** 844 * Returns true if the |uid| holds LOCAL_MAC_ADDRESS permission. 845 */ checkLocalMacAddressPermission(int uid)846 public boolean checkLocalMacAddressPermission(int uid) { 847 return mWifiPermissionsWrapper.getUidPermission( 848 android.Manifest.permission.LOCAL_MAC_ADDRESS, uid) 849 == PackageManager.PERMISSION_GRANTED; 850 } 851 852 /** 853 * Returns true if the |uid| holds NETWORK_SETUP_WIZARD permission. 854 */ checkNetworkSetupWizardPermission(int uid)855 public boolean checkNetworkSetupWizardPermission(int uid) { 856 return mWifiPermissionsWrapper.getUidPermission( 857 android.Manifest.permission.NETWORK_SETUP_WIZARD, uid) 858 == PackageManager.PERMISSION_GRANTED; 859 } 860 861 /** 862 * Returns true if the |uid| holds NETWORK_STACK permission. 863 */ checkNetworkStackPermission(int uid)864 public boolean checkNetworkStackPermission(int uid) { 865 return mWifiPermissionsWrapper.getUidPermission( 866 android.Manifest.permission.NETWORK_STACK, uid) 867 == PackageManager.PERMISSION_GRANTED; 868 } 869 870 /** 871 * Returns true if the |uid| holds MAINLINE_NETWORK_STACK permission. 872 */ checkMainlineNetworkStackPermission(int uid)873 public boolean checkMainlineNetworkStackPermission(int uid) { 874 return mWifiPermissionsWrapper.getUidPermission( 875 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, uid) 876 == PackageManager.PERMISSION_GRANTED; 877 } 878 879 /** 880 * Returns true if the |uid| holds NETWORK_MANAGED_PROVISIONING permission. 881 */ checkNetworkManagedProvisioningPermission(int uid)882 public boolean checkNetworkManagedProvisioningPermission(int uid) { 883 return mWifiPermissionsWrapper.getUidPermission( 884 android.Manifest.permission.NETWORK_MANAGED_PROVISIONING, uid) 885 == PackageManager.PERMISSION_GRANTED; 886 } 887 888 /** 889 * Returns true if the |uid| holds NETWORK_CARRIER_PROVISIONING permission. 890 */ checkNetworkCarrierProvisioningPermission(int uid)891 public boolean checkNetworkCarrierProvisioningPermission(int uid) { 892 return mWifiPermissionsWrapper.getUidPermission( 893 android.Manifest.permission.NETWORK_CARRIER_PROVISIONING, uid) 894 == PackageManager.PERMISSION_GRANTED; 895 } 896 897 /** 898 * Returns true if the |uid| holds READ_WIFI_CREDENTIAL permission. 899 */ checkReadWifiCredentialPermission(int uid)900 public boolean checkReadWifiCredentialPermission(int uid) { 901 return mWifiPermissionsWrapper.getUidPermission( 902 android.Manifest.permission.READ_WIFI_CREDENTIAL, uid) 903 == PackageManager.PERMISSION_GRANTED; 904 } 905 906 /** 907 * Returns true if the |uid| holds CAMERA permission. 908 */ checkCameraPermission(int uid)909 public boolean checkCameraPermission(int uid) { 910 return mWifiPermissionsWrapper.getUidPermission( 911 android.Manifest.permission.CAMERA, uid) 912 == PackageManager.PERMISSION_GRANTED; 913 } 914 915 /** 916 * Returns true if the |callingUid|/\callingPackage| holds SYSTEM_ALERT_WINDOW permission. 917 */ checkSystemAlertWindowPermission(int callingUid, String callingPackage)918 public boolean checkSystemAlertWindowPermission(int callingUid, String callingPackage) { 919 final int mode = mAppOps.noteOp(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW, callingUid, 920 callingPackage, null, null); 921 if (mode == AppOpsManager.MODE_DEFAULT) { 922 return mWifiPermissionsWrapper.getUidPermission( 923 Manifest.permission.SYSTEM_ALERT_WINDOW, callingUid) 924 == PackageManager.PERMISSION_GRANTED; 925 } 926 return mode == AppOpsManager.MODE_ALLOWED; 927 } 928 929 /** 930 * Returns the DevicePolicyManager from context 931 */ retrieveDevicePolicyManagerFromContext(Context context)932 public static DevicePolicyManager retrieveDevicePolicyManagerFromContext(Context context) { 933 DevicePolicyManager devicePolicyManager = 934 context.getSystemService(DevicePolicyManager.class); 935 if (devicePolicyManager == null 936 && context.getPackageManager().hasSystemFeature( 937 PackageManager.FEATURE_DEVICE_ADMIN)) { 938 Log.w(TAG, "Error retrieving DPM service"); 939 } 940 return devicePolicyManager; 941 } 942 943 @Nullable createPackageContextAsUser(int uid)944 private Context createPackageContextAsUser(int uid) { 945 Context userContext = null; 946 try { 947 userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0, 948 UserHandle.getUserHandleForUid(uid)); 949 } catch (PackageManager.NameNotFoundException e) { 950 Log.e(TAG, "Unknown package name"); 951 return null; 952 } 953 if (userContext == null) { 954 Log.e(TAG, "Unable to retrieve user context for " + uid); 955 return null; 956 } 957 return userContext; 958 } 959 retrieveDevicePolicyManagerFromUserContext(int uid)960 private DevicePolicyManager retrieveDevicePolicyManagerFromUserContext(int uid) { 961 long ident = Binder.clearCallingIdentity(); 962 try { 963 Context userContext = createPackageContextAsUser(uid); 964 if (userContext == null) return null; 965 return retrieveDevicePolicyManagerFromContext(userContext); 966 } finally { 967 Binder.restoreCallingIdentity(ident); 968 } 969 } 970 971 @Nullable getDeviceOwner()972 private Pair<UserHandle, ComponentName> getDeviceOwner() { 973 DevicePolicyManager devicePolicyManager = 974 retrieveDevicePolicyManagerFromContext(mContext); 975 if (devicePolicyManager == null) return null; 976 long ident = Binder.clearCallingIdentity(); 977 UserHandle deviceOwnerUser = null; 978 ComponentName deviceOwnerComponent = null; 979 try { 980 deviceOwnerUser = devicePolicyManager.getDeviceOwnerUser(); 981 deviceOwnerComponent = devicePolicyManager.getDeviceOwnerComponentOnAnyUser(); 982 } finally { 983 Binder.restoreCallingIdentity(ident); 984 } 985 if (deviceOwnerUser == null || deviceOwnerComponent == null) return null; 986 987 if (deviceOwnerComponent.getPackageName() == null) { 988 // shouldn't happen 989 Log.wtf(TAG, "no package name on device owner component: " + deviceOwnerComponent); 990 return null; 991 } 992 return new Pair<>(deviceOwnerUser, deviceOwnerComponent); 993 } 994 995 /** 996 * Returns {@code true} if the calling {@code uid} and {@code packageName} is the device owner. 997 */ isDeviceOwner(int uid, @Nullable String packageName)998 public boolean isDeviceOwner(int uid, @Nullable String packageName) { 999 // Cannot determine if the app is DO/PO if packageName is null. So, will return false to be 1000 // safe. 1001 if (packageName == null) { 1002 Log.e(TAG, "isDeviceOwner: packageName is null, returning false"); 1003 return false; 1004 } 1005 Pair<UserHandle, ComponentName> deviceOwner = getDeviceOwner(); 1006 if (mVerboseLoggingEnabled) Log.v(TAG, "deviceOwner:" + deviceOwner); 1007 1008 // no device owner 1009 if (deviceOwner == null) return false; 1010 1011 return deviceOwner.first.equals(UserHandle.getUserHandleForUid(uid)) 1012 && deviceOwner.second.getPackageName().equals(packageName); 1013 } 1014 1015 /** 1016 * Returns {@code true} if the calling {@code uid} is the device owner. 1017 */ isDeviceOwner(int uid)1018 public boolean isDeviceOwner(int uid) { 1019 Pair<UserHandle, ComponentName> deviceOwner = getDeviceOwner(); 1020 1021 // no device owner 1022 if (deviceOwner == null) return false; 1023 1024 // device owner belowngs to wrong user 1025 if (!deviceOwner.first.equals(UserHandle.getUserHandleForUid(uid))) return false; 1026 1027 // finally, check uid 1028 String deviceOwnerPackageName = deviceOwner.second.getPackageName(); 1029 String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); 1030 if (mVerboseLoggingEnabled) { 1031 Log.v(TAG, "Packages for uid " + uid + ":" + Arrays.toString(packageNames)); 1032 } 1033 if (packageNames == null) { 1034 Log.w(TAG, "isDeviceOwner(): could not find packages for packageName=" 1035 + deviceOwnerPackageName + " uid=" + uid); 1036 return false; 1037 } 1038 for (String packageName : packageNames) { 1039 if (deviceOwnerPackageName.equals(packageName)) return true; 1040 } 1041 1042 return false; 1043 } 1044 1045 /** 1046 * Returns {@code true} if the calling {@code uid} is the OEM privileged admin. 1047 * 1048 * The admin must be allowlisted in the wifi overlay and signed with system cert. 1049 */ 1050 @RequiresApi(Build.VERSION_CODES.TIRAMISU) isOemPrivilegedAdmin(int uid)1051 public boolean isOemPrivilegedAdmin(int uid) { 1052 synchronized (mOemPrivilegedAdminUidCache) { 1053 int cacheIdx = mOemPrivilegedAdminUidCache.indexOfKey(uid); 1054 if (cacheIdx >= 0) { 1055 return mOemPrivilegedAdminUidCache.valueAt(cacheIdx); 1056 } 1057 } 1058 1059 boolean result = isOemPrivilegedAdminNoCache(uid); 1060 1061 synchronized (mOemPrivilegedAdminUidCache) { 1062 mOemPrivilegedAdminUidCache.put(uid, result); 1063 } 1064 1065 return result; 1066 } 1067 1068 /** 1069 * Returns {@code true} if the calling {@code uid} is the OEM privileged admin. 1070 * 1071 * This method doesn't memoize results, use {@code isOemPrivilegedAdmin} instead. 1072 */ 1073 @RequiresApi(Build.VERSION_CODES.TIRAMISU) isOemPrivilegedAdminNoCache(int uid)1074 private boolean isOemPrivilegedAdminNoCache(int uid) { 1075 Set<String> oemPrivilegedAdmins = new ArraySet<>(mContext.getResources() 1076 .getStringArray(R.array.config_oemPrivilegedWifiAdminPackages)); 1077 PackageManager pm = mContext.getPackageManager(); 1078 String[] packages = pm.getPackagesForUid(uid); 1079 if (packages == null || Arrays.stream(packages).noneMatch(oemPrivilegedAdmins::contains)) { 1080 return false; 1081 } 1082 1083 return pm.checkSignatures(uid, Process.SYSTEM_UID) == PackageManager.SIGNATURE_MATCH; 1084 } 1085 1086 /** 1087 * Returns true if the |callingUid|/|callingPackage| is the profile owner. 1088 */ isProfileOwner(int uid, @Nullable String packageName)1089 public boolean isProfileOwner(int uid, @Nullable String packageName) { 1090 // Cannot determine if the app is DO/PO if packageName is null. So, will return false to be 1091 // safe. 1092 if (packageName == null) { 1093 Log.e(TAG, "isProfileOwner: packageName is null, returning false"); 1094 return false; 1095 } 1096 DevicePolicyManager devicePolicyManager = 1097 retrieveDevicePolicyManagerFromUserContext(uid); 1098 if (devicePolicyManager == null) return false; 1099 return devicePolicyManager.isProfileOwnerApp(packageName); 1100 } 1101 1102 /** 1103 * Returns {@code true} if the calling {@code uid} is the profile owner of 1104 * an organization owned device. 1105 */ isProfileOwnerOfOrganizationOwnedDevice(int uid)1106 public boolean isProfileOwnerOfOrganizationOwnedDevice(int uid) { 1107 DevicePolicyManager devicePolicyManager = 1108 retrieveDevicePolicyManagerFromUserContext(uid); 1109 if (devicePolicyManager == null) return false; 1110 1111 // this relies on having only one PO on COPE device. 1112 if (!devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()) { 1113 return false; 1114 } 1115 String[] packages = mContext.getPackageManager().getPackagesForUid(uid); 1116 if (packages == null) { 1117 Log.w(TAG, "isProfileOwnerOfOrganizationOwnedDevice(): could not find packages for uid=" 1118 + uid); 1119 return false; 1120 } 1121 for (String packageName : packages) { 1122 if (devicePolicyManager.isProfileOwnerApp(packageName)) return true; 1123 } 1124 return false; 1125 } 1126 1127 /** 1128 * Returns {@code true} if the calling {@code uid} and {@code packageName} is the device owner 1129 * or the profile owner of an organization owned device. 1130 */ isOrganizationOwnedDeviceAdmin(int uid, @Nullable String packageName)1131 public boolean isOrganizationOwnedDeviceAdmin(int uid, @Nullable String packageName) { 1132 boolean isDeviceOwner = 1133 packageName == null ? isDeviceOwner(uid) : isDeviceOwner(uid, packageName); 1134 return isDeviceOwner || isProfileOwnerOfOrganizationOwnedDevice(uid); 1135 } 1136 1137 /** Helper method to check if the entity initiating the binder call is a system app. */ isSystem(String packageName, int uid)1138 public boolean isSystem(String packageName, int uid) { 1139 long ident = Binder.clearCallingIdentity(); 1140 try { 1141 ApplicationInfo info = mContext.getPackageManager().getApplicationInfoAsUser( 1142 packageName, 0, UserHandle.getUserHandleForUid(uid)); 1143 return (info.flags & APP_INFO_FLAGS_SYSTEM_APP) != 0; 1144 } catch (PackageManager.NameNotFoundException e) { 1145 // In case of exception, assume unknown app (more strict checking) 1146 // Note: This case will never happen since checkPackage is 1147 // called to verify validity before checking App's version. 1148 } finally { 1149 Binder.restoreCallingIdentity(ident); 1150 } 1151 return false; 1152 } 1153 1154 /** 1155 * Checks if the given UID belongs to the current foreground or device owner user. This is 1156 * used to prevent apps running in background users from modifying network 1157 * configurations. 1158 * <p> 1159 * UIDs belonging to system internals (such as SystemUI) are always allowed, 1160 * since they always run as {@link UserHandle#USER_SYSTEM}. 1161 * 1162 * @param uid uid of the app. 1163 * @return true if the given UID belongs to the current foreground user, 1164 * otherwise false. 1165 */ doesUidBelongToCurrentUserOrDeviceOwner(int uid)1166 public boolean doesUidBelongToCurrentUserOrDeviceOwner(int uid) { 1167 boolean isCurrentProfile = doesUidBelongToUser( 1168 uid, mWifiPermissionsWrapper.getCurrentUser()); 1169 if (!isCurrentProfile) { 1170 // Fix for b/174749461 1171 EventLog.writeEvent(0x534e4554, "174749461", -1, 1172 "Non foreground user trying to modify wifi configuration"); 1173 } 1174 return isCurrentProfile || isDeviceOwner(uid); 1175 } 1176 1177 /** 1178 * Check if the current user is a guest user 1179 * @return true if the current user is a guest user, false otherwise. 1180 */ isGuestUser()1181 public boolean isGuestUser() { 1182 UserManager userManager = mContext.createContextAsUser( 1183 UserHandle.of(mWifiPermissionsWrapper.getCurrentUser()), 0) 1184 .getSystemService(UserManager.class); 1185 if (userManager == null) { 1186 return true; 1187 } 1188 return userManager.isGuestUser(); 1189 } 1190 1191 /** 1192 * Checks if the given UID belongs to the given user ID. This is 1193 * used to prevent apps running in other users from modifying network configurations belonging 1194 * to the given user. 1195 * <p> 1196 * UIDs belonging to system internals (such as SystemUI) are always allowed, 1197 * since they always run as {@link UserHandle#USER_SYSTEM}. 1198 * 1199 * @param uid uid to check 1200 * @param userId user to check against 1201 * @return true if the given UID belongs to the given user. 1202 */ doesUidBelongToUser(int uid, int userId)1203 public boolean doesUidBelongToUser(int uid, int userId) { 1204 if (UserHandle.getAppId(uid) == android.os.Process.SYSTEM_UID 1205 // UIDs with the NETWORK_SETTINGS permission are always allowed since they are 1206 // acting on behalf of the user. 1207 || checkNetworkSettingsPermission(uid)) { 1208 return true; 1209 } 1210 UserHandle uidHandle = UserHandle.getUserHandleForUid(uid); 1211 UserHandle userHandle = UserHandle.of(userId); 1212 return uidHandle.equals(userHandle) 1213 || mUserManager.isSameProfileGroup(uidHandle, userHandle); 1214 } 1215 1216 /** 1217 * Sets the verbose logging level. 1218 */ enableVerboseLogging(boolean enabled)1219 public void enableVerboseLogging(boolean enabled) { 1220 mVerboseLoggingEnabled = enabled; 1221 } 1222 1223 /** 1224 * Return the corresponding WifiCallerType enum used for WifiStatsLog metrics logging. 1225 */ 1226 @RequiresApi(Build.VERSION_CODES.S) getWifiCallerType(@onNull AttributionSource attributionSource)1227 public int getWifiCallerType(@NonNull AttributionSource attributionSource) { 1228 if (!SdkLevel.isAtLeastS() || attributionSource == null) { 1229 return 0; 1230 } 1231 return getWifiCallerType(attributionSource.getUid(), attributionSource.getPackageName()); 1232 } 1233 1234 /** 1235 * Return the corresponding WifiCallerType enum used for WifiStatsLog metrics logging. 1236 */ getWifiCallerType(int uid, String packageName)1237 public int getWifiCallerType(int uid, String packageName) { 1238 // TODO: Need to hardcode enum values for now since no atom is actually using this enum. 1239 // Once the first atom start using it, replace the hardcoded values with constants generated 1240 // in WifiStatsLog 1241 if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid)) { 1242 return 1; // SETTINGS 1243 } else if (isAdmin(uid, packageName)) { 1244 return 2; // ADMIN 1245 } else if (checkEnterCarModePrioritized(uid)) { 1246 return 3; // AUTOMOTIVE 1247 } else if (mContext.getPackageManager().checkSignatures(uid, Process.SYSTEM_UID) 1248 == PackageManager.SIGNATURE_MATCH) { 1249 return 4; // SIGNATURE 1250 } else if (isSystem(packageName, uid)) { 1251 return 5; // SYSTEM 1252 } 1253 return 6; // OTHERS 1254 } 1255 1256 /** 1257 * Returns true if the |callingUid|/|callingPackage| is an admin. 1258 */ isAdmin(int uid, @Nullable String packageName)1259 public boolean isAdmin(int uid, @Nullable String packageName) { 1260 // Cannot determine if the app is an admin if packageName is null. 1261 // So, will return false to be safe. 1262 if (packageName == null) { 1263 Log.e(TAG, "isAdmin: packageName is null, returning false"); 1264 return false; 1265 } 1266 boolean isOemPrivilegedAdmin = (SdkLevel.isAtLeastT()) ? isOemPrivilegedAdmin(uid) : false; 1267 1268 return isDeviceOwner(uid, packageName) || isProfileOwner(uid, packageName) 1269 || isOemPrivilegedAdmin; 1270 } 1271 1272 /** 1273 * Returns true if a package is a device admin. 1274 * Note that device admin is a deprecated concept so this should only be used in very specific 1275 * cases which require such checks. 1276 */ isLegacyDeviceAdmin(int uid, String packageName)1277 public boolean isLegacyDeviceAdmin(int uid, String packageName) { 1278 if (packageName == null) { 1279 Log.e(TAG, "isLegacyDeviceAdmin: packageName is null, returning false"); 1280 return false; 1281 } 1282 DevicePolicyManager devicePolicyManager = 1283 retrieveDevicePolicyManagerFromUserContext(uid); 1284 if (devicePolicyManager == null) return false; 1285 return devicePolicyManager.packageHasActiveAdmins(packageName); 1286 } 1287 1288 /** 1289 * Returns true if the device may not connect to the configuration due to admin restriction 1290 */ isAdminRestrictedNetwork(@ullable WifiConfiguration config)1291 public boolean isAdminRestrictedNetwork(@Nullable WifiConfiguration config) { 1292 if (config == null || !SdkLevel.isAtLeastT()) { 1293 return false; 1294 } 1295 1296 DevicePolicyManager devicePolicyManager = 1297 WifiPermissionsUtil.retrieveDevicePolicyManagerFromContext(mContext); 1298 if (devicePolicyManager == null) return false; 1299 1300 int adminMinimumSecurityLevel = 0; 1301 WifiSsidPolicy policy; 1302 long ident = Binder.clearCallingIdentity(); 1303 try { 1304 adminMinimumSecurityLevel = devicePolicyManager.getMinimumRequiredWifiSecurityLevel(); 1305 policy = devicePolicyManager.getWifiSsidPolicy(); 1306 } finally { 1307 Binder.restoreCallingIdentity(ident); 1308 } 1309 1310 //check minimum security level restriction 1311 if (adminMinimumSecurityLevel != 0) { 1312 boolean securityRestrictionPassed = false; 1313 for (SecurityParams params : config.getSecurityParamsList()) { 1314 int securityLevel = WifiInfo.convertSecurityTypeToDpmWifiSecurity( 1315 WifiInfo.convertWifiConfigurationSecurityType(params.getSecurityType())); 1316 1317 // Skip unknown security type since security level cannot be determined. 1318 if (securityLevel == WifiInfo.DPM_SECURITY_TYPE_UNKNOWN) continue; 1319 1320 if (adminMinimumSecurityLevel <= securityLevel) { 1321 securityRestrictionPassed = true; 1322 break; 1323 } 1324 } 1325 if (!securityRestrictionPassed) { 1326 return true; 1327 } 1328 } 1329 1330 //check SSID restriction 1331 if (policy != null) { 1332 //skip SSID restriction check for Osu and Passpoint networks 1333 if (config.osu || config.isPasspoint()) return false; 1334 1335 int policyType = policy.getPolicyType(); 1336 Set<WifiSsid> ssids = policy.getSsids(); 1337 WifiSsid ssid = WifiSsid.fromString(config.SSID); 1338 1339 if (policyType == WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST 1340 && !ssids.contains(ssid)) { 1341 return true; 1342 } 1343 if (policyType == WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST 1344 && ssids.contains(ssid)) { 1345 return true; 1346 } 1347 } 1348 return false; 1349 } 1350 1351 /** 1352 * Returns the foreground userId 1353 */ getCurrentUser()1354 public int getCurrentUser() { 1355 //set the default to undefined user id (UserHandle.USER_NULL) 1356 int user = -10000; 1357 long ident = Binder.clearCallingIdentity(); 1358 try { 1359 user = mWifiPermissionsWrapper.getCurrentUser(); 1360 } finally { 1361 Binder.restoreCallingIdentity(ident); 1362 } 1363 return user; 1364 } 1365 1366 /** Whether the uid is signed with the same key as the platform. */ isSignedWithPlatformKey(int uid)1367 public boolean isSignedWithPlatformKey(int uid) { 1368 return mContext.getPackageManager().checkSignatures(uid, Process.SYSTEM_UID) 1369 == PackageManager.SIGNATURE_MATCH; 1370 } 1371 } 1372