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