diff options
author | Sarah Chin <sarahchin@google.com> | 2022-05-07 23:30:31 -0700 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-05-16 21:11:42 +0000 |
commit | 0a7b58f5ac08f01535201f9341b84bdf44eb92ef (patch) | |
tree | f16f925afd51566786821fe8a87ff4d4007ca421 | |
parent | a3bf26d6bc71d61566eabb842b6f420c3d5fcfb6 (diff) | |
download | base-0a7b58f5ac08f01535201f9341b84bdf44eb92ef.tar.gz |
Update ServiceState broadcast for location permissions
Add extra checks for master location switch and location bypass packages
and send broadcasts accordingly.
Test: Verify location is sanitized using testapp
Test: Verify privacy dashboard with MLS on/off
Test: Verify location is sanitized/unsanitized with bypass list
Bug: 230919427
Bug: 210118427
Change-Id: I9784527d6d79235830f562c1944562f5a6ac1fb3
Merged-In: I9784527d6d79235830f562c1944562f5a6ac1fb3
(cherry picked from commit ac5f03c07fafe1a9d5dba89737297da7c74214cf)
Merged-In: I9784527d6d79235830f562c1944562f5a6ac1fb3
-rw-r--r-- | core/res/res/values/config.xml | 8 | ||||
-rw-r--r-- | core/res/res/values/symbols.xml | 2 | ||||
-rw-r--r-- | services/core/java/com/android/server/TelephonyRegistry.java | 102 | ||||
-rw-r--r-- | telephony/common/android/telephony/LocationAccessPolicy.java | 13 |
4 files changed, 95 insertions, 30 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 2ad2a5cfd285..21c6f087a2d4 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -5308,4 +5308,12 @@ </string> <integer name="config_chooser_max_targets_per_row">4</integer> + + <!-- List of system components which are allowed to receive ServiceState entries in an + un-sanitized form, even if the location toggle is off. This is intended ONLY for system + components, such as the telephony stack, which require access to the full ServiceState for + tasks such as network registration. --> + <string-array name="config_serviceStateLocationAllowedPackages"> + <item>"com.android.phone"</item> + </string-array> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index af8472f9a90a..a1ed949b9472 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4492,6 +4492,6 @@ <java-symbol type="array" name="config_roundedCornerBottomRadiusAdjustmentArray" /> <java-symbol type="bool" name="config_secondaryBuiltInDisplayIsRound" /> <java-symbol type="array" name="config_builtInDisplayIsRoundArray" /> - + <java-symbol type="array" name="config_serviceStateLocationAllowedPackages" /> <java-symbol type="dimen" name="status_bar_height_default" /> </resources> diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index a8a24f19f6ba..9d5d167da722 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -2891,42 +2891,88 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { Binder.restoreCallingIdentity(ident); } + // Send the broadcast exactly once to all possible disjoint sets of apps. + // If the location master switch is on, broadcast the ServiceState 4 times: + // - Full ServiceState sent to apps with ACCESS_FINE_LOCATION and READ_PHONE_STATE + // - Full ServiceState sent to apps with ACCESS_FINE_LOCATION and + // READ_PRIVILEGED_PHONE_STATE but not READ_PHONE_STATE + // - Sanitized ServiceState sent to apps with READ_PHONE_STATE but not ACCESS_FINE_LOCATION + // - Sanitized ServiceState sent to apps with READ_PRIVILEGED_PHONE_STATE but neither + // READ_PHONE_STATE nor ACCESS_FINE_LOCATION + // If the location master switch is off, broadcast the ServiceState multiple times: + // - Full ServiceState sent to all apps permitted to bypass the location master switch if + // they have either READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE + // - Sanitized ServiceState sent to all other apps with READ_PHONE_STATE + // - Sanitized ServiceState sent to all other apps with READ_PRIVILEGED_PHONE_STATE but not + // READ_PHONE_STATE + if (Binder.withCleanCallingIdentity(() -> + LocationAccessPolicy.isLocationModeEnabled(mContext, mContext.getUserId()))) { + Intent fullIntent = createServiceStateIntent(state, subId, phoneId, false); + mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( + fullIntent, + new String[]{Manifest.permission.READ_PHONE_STATE, + Manifest.permission.ACCESS_FINE_LOCATION}); + mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( + fullIntent, + new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + Manifest.permission.ACCESS_FINE_LOCATION}, + new String[]{Manifest.permission.READ_PHONE_STATE}); + + Intent sanitizedIntent = createServiceStateIntent(state, subId, phoneId, true); + mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( + sanitizedIntent, + new String[]{Manifest.permission.READ_PHONE_STATE}, + new String[]{Manifest.permission.ACCESS_FINE_LOCATION}); + mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( + sanitizedIntent, + new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE}, + new String[]{Manifest.permission.READ_PHONE_STATE, + Manifest.permission.ACCESS_FINE_LOCATION}); + } else { + String[] locationBypassPackages = Binder.withCleanCallingIdentity(() -> + LocationAccessPolicy.getLocationBypassPackages(mContext)); + for (String locationBypassPackage : locationBypassPackages) { + Intent fullIntent = createServiceStateIntent(state, subId, phoneId, false); + fullIntent.setPackage(locationBypassPackage); + mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( + fullIntent, + new String[]{Manifest.permission.READ_PHONE_STATE}); + mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( + fullIntent, + new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE}, + new String[]{Manifest.permission.READ_PHONE_STATE}); + } + + Intent sanitizedIntent = createServiceStateIntent(state, subId, phoneId, true); + mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( + sanitizedIntent, + new String[]{Manifest.permission.READ_PHONE_STATE}, + new String[]{/* no excluded permissions */}, + locationBypassPackages); + mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( + sanitizedIntent, + new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE}, + new String[]{Manifest.permission.READ_PHONE_STATE}, + locationBypassPackages); + } + } + + private Intent createServiceStateIntent(ServiceState state, int subId, int phoneId, + boolean sanitizeLocation) { Intent intent = new Intent(Intent.ACTION_SERVICE_STATE); intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); Bundle data = new Bundle(); - state.fillInNotifierBundle(data); + if (sanitizeLocation) { + state.createLocationInfoSanitizedCopy(true).fillInNotifierBundle(data); + } else { + state.fillInNotifierBundle(data); + } intent.putExtras(data); - // Pass the subscription along with the intent. intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId); intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId); intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId); - - // Send the broadcast twice -- once for all apps with READ_PHONE_STATE, then again - // for all apps with READ_PRIVILEGED_PHONE_STATE but not READ_PHONE_STATE. - // Do this again twice, the first time for apps with ACCESS_FINE_LOCATION, then again with - // the location-sanitized service state for all apps without ACCESS_FINE_LOCATION. - // This ensures that any app holding either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE - // get this broadcast exactly once, and we are not exposing location without permission. - mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent, - new String[] {Manifest.permission.READ_PHONE_STATE, - Manifest.permission.ACCESS_FINE_LOCATION}); - mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent, - new String[] {Manifest.permission.READ_PRIVILEGED_PHONE_STATE, - Manifest.permission.ACCESS_FINE_LOCATION}, - new String[] {Manifest.permission.READ_PHONE_STATE}); - - // Replace bundle with location-sanitized ServiceState - data = new Bundle(); - state.createLocationInfoSanitizedCopy(true).fillInNotifierBundle(data); - intent.putExtras(data); - mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent, - new String[] {Manifest.permission.READ_PHONE_STATE}, - new String[] {Manifest.permission.ACCESS_FINE_LOCATION}); - mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent, - new String[] {Manifest.permission.READ_PRIVILEGED_PHONE_STATE}, - new String[] {Manifest.permission.READ_PHONE_STATE, - Manifest.permission.ACCESS_FINE_LOCATION}); + return intent; } private void broadcastSignalStrengthChanged(SignalStrength signalStrength, int phoneId, diff --git a/telephony/common/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java index 85d59a216f25..9dfb0cc289ee 100644 --- a/telephony/common/android/telephony/LocationAccessPolicy.java +++ b/telephony/common/android/telephony/LocationAccessPolicy.java @@ -361,7 +361,10 @@ public final class LocationAccessPolicy { return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context, pid, uid); } - private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) { + /** + * @return Whether location is enabled for the given user. + */ + public static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) { LocationManager locationManager = context.getSystemService(LocationManager.class); if (locationManager == null) { Log.w(TAG, "Couldn't get location manager, denying location access"); @@ -370,6 +373,14 @@ public final class LocationAccessPolicy { return locationManager.isLocationEnabledForUser(UserHandle.of(userId)); } + /** + * @return An array of packages that are always allowed to access location. + */ + public static @NonNull String[] getLocationBypassPackages(@NonNull Context context) { + return context.getResources().getStringArray( + com.android.internal.R.array.config_serviceStateLocationAllowedPackages); + } + private static boolean checkInteractAcrossUsersFull( @NonNull Context context, int pid, int uid) { return checkManifestPermission(context, pid, uid, |