diff options
| author | 2020-01-16 10:50:14 -0800 | |
|---|---|---|
| committer | 2020-01-16 10:50:14 -0800 | |
| commit | bfd1f68bdcf0fb5536e902ee7e14fab61f2086b6 (patch) | |
| tree | d9796c3f9a17a27284350180463fe7a45fa2a9e3 | |
| parent | dcf811600ffb29b3763065595cb57fa117d1a0c5 (diff) | |
Refactor location permissions code
This simplification relies on the fact that we no longer disallow
satellite based location from being coarsened and used for clients with
the coarse permission only. This allows us to remove some very
convoluted permission checking.
Test: presubmits + manual
Change-Id: Icb9529373914949a6f788535e222f1f3748fa10a
| -rw-r--r-- | services/core/java/com/android/server/LocationManagerService.java | 165 |
1 files changed, 56 insertions, 109 deletions
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index dc393d1609de..d0a613c3a7cd 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -16,6 +16,8 @@ package com.android.server; +import static android.Manifest.permission.ACCESS_COARSE_LOCATION; +import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.location.LocationManager.FUSED_PROVIDER; import static android.location.LocationManager.GPS_PROVIDER; @@ -83,6 +85,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageMonitor; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; @@ -1396,20 +1399,19 @@ public class LocationManagerService extends ILocationManager.Stub { private String getResolutionPermission(int resolutionLevel) { switch (resolutionLevel) { case RESOLUTION_LEVEL_FINE: - return android.Manifest.permission.ACCESS_FINE_LOCATION; + return ACCESS_FINE_LOCATION; case RESOLUTION_LEVEL_COARSE: - return android.Manifest.permission.ACCESS_COARSE_LOCATION; + return ACCESS_COARSE_LOCATION; default: return null; } } private int getAllowedResolutionLevel(int pid, int uid) { - if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, - pid, uid) == PERMISSION_GRANTED) { + if (mContext.checkPermission(ACCESS_FINE_LOCATION, pid, uid) == PERMISSION_GRANTED) { return RESOLUTION_LEVEL_FINE; - } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION, - pid, uid) == PERMISSION_GRANTED) { + } else if (mContext.checkPermission(ACCESS_COARSE_LOCATION, pid, uid) + == PERMISSION_GRANTED) { return RESOLUTION_LEVEL_COARSE; } else { return RESOLUTION_LEVEL_NONE; @@ -1420,59 +1422,28 @@ public class LocationManagerService extends ILocationManager.Stub { return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid()); } - private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) { - if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) { - throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission"); - } + private boolean checkCallingOrSelfLocationPermission() { + return mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED + || mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) + == PERMISSION_GRANTED; } - @GuardedBy("mLock") - private int getMinimumResolutionLevelForProviderUseLocked(String provider) { - if (GPS_PROVIDER.equals(provider) || PASSIVE_PROVIDER.equals(provider)) { - // gps and passive providers require FINE permission - return RESOLUTION_LEVEL_FINE; - } else if (NETWORK_PROVIDER.equals(provider) || FUSED_PROVIDER.equals(provider)) { - // network and fused providers are ok with COARSE or FINE - return RESOLUTION_LEVEL_COARSE; - } else { - for (LocationProviderManager lp : mProviderManagers) { - if (!lp.getName().equals(provider)) { - continue; - } - - ProviderProperties properties = lp.getProperties(); - if (properties != null) { - if (properties.mRequiresSatellite) { - // provider requiring satellites require FINE permission - return RESOLUTION_LEVEL_FINE; - } else if (properties.mRequiresNetwork || properties.mRequiresCell) { - // provider requiring network and or cell require COARSE or FINE - return RESOLUTION_LEVEL_COARSE; - } - } - } + private void enforceCallingOrSelfLocationPermission() { + if (checkCallingOrSelfLocationPermission()) { + return; } - return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE + throw new SecurityException("uid " + Binder.getCallingUid() + " does not have " + + ACCESS_COARSE_LOCATION + " or " + ACCESS_FINE_LOCATION + "."); } - @GuardedBy("mLock") - private void checkResolutionLevelIsSufficientForProviderUseLocked(int allowedResolutionLevel, - String providerName) { - int requiredResolutionLevel = getMinimumResolutionLevelForProviderUseLocked(providerName); - if (allowedResolutionLevel < requiredResolutionLevel) { - switch (requiredResolutionLevel) { - case RESOLUTION_LEVEL_FINE: - throw new SecurityException("\"" + providerName + "\" location provider " + - "requires ACCESS_FINE_LOCATION permission."); - case RESOLUTION_LEVEL_COARSE: - throw new SecurityException("\"" + providerName + "\" location provider " + - "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission."); - default: - throw new SecurityException("Insufficient permission for \"" + providerName + - "\" location provider."); - } + private void enforceCallingOrSelfPackageName(String packageName) { + int uid = Binder.getCallingUid(); + if (ArrayUtils.contains(mPackageManager.getPackagesForUid(uid), packageName)) { + return; } + + throw new SecurityException("invalid package \"" + packageName + "\" for uid " + uid); } public static int resolutionLevelToOp(int allowedResolutionLevel) { @@ -1548,7 +1519,10 @@ public class LocationManagerService extends ILocationManager.Stub { */ @Override public List<String> getProviders(Criteria criteria, boolean enabledOnly) { - int allowedResolutionLevel = getCallerAllowedResolutionLevel(); + if (!checkCallingOrSelfLocationPermission()) { + return Collections.emptyList(); + } + synchronized (mLock) { ArrayList<String> providers = new ArrayList<>(mProviderManagers.size()); for (LocationProviderManager manager : mProviderManagers) { @@ -1556,9 +1530,6 @@ public class LocationManagerService extends ILocationManager.Stub { if (FUSED_PROVIDER.equals(name)) { continue; } - if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUseLocked(name)) { - continue; - } if (enabledOnly && !manager.isUseable()) { continue; } @@ -2002,33 +1973,18 @@ public class LocationManagerService extends ILocationManager.Stub { return sanitizedRequest; } - private void checkPackageName(String packageName) { - if (packageName == null) { - throw new SecurityException("invalid package name: " + null); - } - int uid = Binder.getCallingUid(); - String[] packages = mPackageManager.getPackagesForUid(uid); - if (packages == null) { - throw new SecurityException("invalid UID " + uid); - } - for (String pkg : packages) { - if (packageName.equals(pkg)) return; - } - throw new SecurityException("invalid package name: " + packageName); - } - @Override public void requestLocationUpdates(LocationRequest request, ILocationListener listener, PendingIntent intent, String packageName, String featureId, String listenerIdentifier) { Objects.requireNonNull(listenerIdentifier); + enforceCallingOrSelfLocationPermission(); + enforceCallingOrSelfPackageName(packageName); + synchronized (mLock) { if (request == null) request = DEFAULT_LOCATION_REQUEST; - checkPackageName(packageName); int allowedResolutionLevel = getCallerAllowedResolutionLevel(); - checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel, - request.getProvider()); WorkSource workSource = request.getWorkSource(); if (workSource != null && !workSource.isEmpty()) { mContext.enforceCallingOrSelfPermission( @@ -2135,7 +2091,7 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public void removeUpdates(ILocationListener listener, PendingIntent intent, String packageName) { - checkPackageName(packageName); + enforceCallingOrSelfPackageName(packageName); int pid = Binder.getCallingPid(); int uid = Binder.getCallingUid(); @@ -2197,12 +2153,12 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public Location getLastLocation(LocationRequest r, String packageName, String featureId) { + enforceCallingOrSelfLocationPermission(); + enforceCallingOrSelfPackageName(packageName); + synchronized (mLock) { LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST; int allowedResolutionLevel = getCallerAllowedResolutionLevel(); - checkPackageName(packageName); - checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel, - request.getProvider()); // no need to sanitize this request, as only the provider name is used final int pid = Binder.getCallingPid(); @@ -2348,7 +2304,7 @@ public class LocationManagerService extends ILocationManager.Stub { public boolean injectLocation(Location location) { mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE, "Location Hardware permission not granted to inject location"); - mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, + mContext.enforceCallingPermission(ACCESS_FINE_LOCATION, "Access Fine Location permission not granted to inject Location"); synchronized (mLock) { @@ -2374,17 +2330,14 @@ public class LocationManagerService extends ILocationManager.Stub { String packageName, String featureId, String listenerIdentifier) { Objects.requireNonNull(listenerIdentifier); + mContext.enforceCallingOrSelfPermission(ACCESS_FINE_LOCATION, null); + enforceCallingOrSelfPackageName(packageName); + if (request == null) request = DEFAULT_LOCATION_REQUEST; int allowedResolutionLevel = getCallerAllowedResolutionLevel(); - checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel); if (intent == null) { throw new IllegalArgumentException("invalid pending intent: " + null); } - checkPackageName(packageName); - synchronized (mLock) { - checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel, - request.getProvider()); - } // Require that caller can manage given document boolean callerHasLocationHardwarePermission = mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE) @@ -2430,7 +2383,7 @@ public class LocationManagerService extends ILocationManager.Stub { if (intent == null) { throw new IllegalArgumentException("invalid pending intent: " + null); } - checkPackageName(packageName); + enforceCallingOrSelfPackageName(packageName); if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent); @@ -2517,36 +2470,30 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public boolean sendExtraCommand(String providerName, String command, Bundle extras) { - if (providerName == null) { - // throw NullPointerException to remain compatible with previous implementation - throw new NullPointerException(); - } + Objects.requireNonNull(providerName); + Objects.requireNonNull(command); mContext.enforceCallingOrSelfPermission( Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, null); + enforceCallingOrSelfLocationPermission(); - synchronized (mLock) { - checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(), - providerName); - - mLocationUsageLogger.logLocationApiUsage( - LocationStatsEnums.USAGE_STARTED, - LocationStatsEnums.API_SEND_EXTRA_COMMAND, - providerName); + mLocationUsageLogger.logLocationApiUsage( + LocationStatsEnums.USAGE_STARTED, + LocationStatsEnums.API_SEND_EXTRA_COMMAND, + providerName); - LocationProviderManager manager = getLocationProviderManager(providerName); - if (manager != null) { - manager.sendExtraCommand(Binder.getCallingUid(), Binder.getCallingPid(), command, - extras); - } + LocationProviderManager manager = getLocationProviderManager(providerName); + if (manager != null) { + manager.sendExtraCommand(Binder.getCallingUid(), Binder.getCallingPid(), command, + extras); + } - mLocationUsageLogger.logLocationApiUsage( - LocationStatsEnums.USAGE_ENDED, - LocationStatsEnums.API_SEND_EXTRA_COMMAND, - providerName); + mLocationUsageLogger.logLocationApiUsage( + LocationStatsEnums.USAGE_ENDED, + LocationStatsEnums.API_SEND_EXTRA_COMMAND, + providerName); - return true; - } + return true; } @Override |