diff options
| author | Svetoslav Ganov <svetoslavganov@google.com> | 2017-06-21 17:39:12 +0000 |
|---|---|---|
| committer | Svetoslav Ganov <svetoslavganov@google.com> | 2017-06-21 17:44:45 +0000 |
| commit | 602b29662cd9c4ab1d5483217055885e8d9b8b7c (patch) | |
| tree | 5cbafe30c9c9f64e6bc4ef293fbb7165d242f006 | |
| parent | d9cc11475bf9033090db4476a589459e1576a130 (diff) | |
| download | platform_packages_services_Telephony-oreo-dev.tar.gz platform_packages_services_Telephony-oreo-dev.tar.bz2 platform_packages_services_Telephony-oreo-dev.zip | |
Revert "Properly protect cell location."oreo-dev
This reverts commit d9cc11475bf9033090db4476a589459e1576a130.
bug:38489777
Change-Id: Ib34bfa095fe0ace0deded3ded0ee92d5713147f2
| -rw-r--r-- | src/com/android/phone/LocationAccessPolicy.java | 137 | ||||
| -rw-r--r-- | src/com/android/phone/PhoneInterfaceManager.java | 145 |
2 files changed, 115 insertions, 167 deletions
diff --git a/src/com/android/phone/LocationAccessPolicy.java b/src/com/android/phone/LocationAccessPolicy.java deleted file mode 100644 index 9f863a33f..000000000 --- a/src/com/android/phone/LocationAccessPolicy.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.phone; - -import android.Manifest; -import android.annotation.NonNull; -import android.annotation.UserIdInt; -import android.app.ActivityManager; -import android.app.AppOpsManager; -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.pm.UserInfo; -import android.os.Build; -import android.os.UserHandle; -import android.os.UserManager; -import android.provider.Settings; - -import java.util.List; - -/** - * Helper for performing location access checks. - */ -final class LocationAccessPolicy { - - private LocationAccessPolicy() { - /* do nothing - hide ctor */ - } - - /** - * API to determine if the caller has permissions to get cell location. - * - * @param pkgName Package name of the application requesting access - * @param uid The uid of the package - * @return boolean true or false if permissions is granted - */ - static boolean canAccessCellLocation(@NonNull Context context, @NonNull String pkgName, - int uid) throws SecurityException { - context.getSystemService(AppOpsManager.class).checkPackage(uid, pkgName); - // We always require the location permission and also require the - // location mode to be on for non-legacy apps. Legacy apps are - // required to be in the foreground to at least mitigate the case - // where a legacy app the user is not using tracks their location. - if (!hasUidLocationPermission(context, pkgName, uid) - || (!isLocationModeEnabled(context, UserHandle.getUserId(uid))) - && !isLegacyForeground(context, pkgName)) { - return false; - } - // If the user or profile is current, permission is granted. - // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission. - return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context); - } - - private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) { - return Settings.Secure.getIntForUser(context.getContentResolver(), - Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF, userId) - != Settings.Secure.LOCATION_MODE_OFF; - } - - private static boolean isLegacyForeground(@NonNull Context context, @NonNull String pkgName) { - return isLegacyVersion(context, pkgName) && isForegroundApp(context, pkgName); - } - - private static boolean isLegacyVersion(@NonNull Context context, @NonNull String pkgName) { - try { - if (context.getPackageManager().getApplicationInfo(pkgName, 0) - .targetSdkVersion <= Build.VERSION_CODES.O) { - return true; - } - } catch (PackageManager.NameNotFoundException e) { - // In case of exception, assume known app (more strict checking) - // Note: This case will never happen since checkPackage is - // called to verify validity before checking app's version. - } - return false; - } - - private static boolean isForegroundApp(@NonNull Context context, @NonNull String pkgName) { - final ActivityManager am = context.getSystemService(ActivityManager.class); - final List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1); - if (!tasks.isEmpty()) { - return pkgName.equals(tasks.get(0).topActivity.getPackageName()); - } - return false; - } - - private static boolean checkInteractAcrossUsersFull(@NonNull Context context) { - return context.checkCallingOrSelfPermission( - android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) - == PackageManager.PERMISSION_GRANTED; - } - - private static boolean hasUidLocationPermission(@NonNull Context context, - @NonNull String pkgName, int uid) { - // Grating ACCESS_FINE_LOCATION to an app automatically grants it ACCESS_COARSE_LOCATION. - if ((context.checkCallingOrSelfPermission( - Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED)) { - final int opCode = AppOpsManager.permissionToOpCode( - Manifest.permission.ACCESS_COARSE_LOCATION); - if (opCode != AppOpsManager.OP_NONE) { - return context.getSystemService(AppOpsManager.class).noteOp(opCode, uid, pkgName) - == AppOpsManager.MODE_ALLOWED; - } - } - return false; - } - - private static boolean isCurrentProfile(@NonNull Context context, int uid) { - final int currentUser = ActivityManager.getCurrentUser(); - final int callingUserId = UserHandle.getUserId(uid); - if (callingUserId == currentUser) { - return true; - } else { - List<UserInfo> userProfiles = context.getSystemService( - UserManager.class).getProfiles(currentUser); - for (UserInfo user: userProfiles) { - if (user.id == callingUserId) { - return true; - } - } - } - return false; - } -} diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java index 975250284..92da36f85 100644 --- a/src/com/android/phone/PhoneInterfaceManager.java +++ b/src/com/android/phone/PhoneInterfaceManager.java @@ -19,6 +19,7 @@ package com.android.phone; import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY; import android.Manifest.permission; +import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.PendingIntent; import android.content.ComponentName; @@ -34,6 +35,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.Process; import android.os.PersistableBundle; import android.os.ResultReceiver; import android.os.ServiceManager; @@ -1627,23 +1629,47 @@ public class PhoneInterfaceManager extends ITelephony.Stub { @Override public Bundle getCellLocation(String callingPackage) { - if (!LocationAccessPolicy.canAccessCellLocation(mPhone.getContext(), - callingPackage, Binder.getCallingUid())) { + enforceFineOrCoarseLocationPermission("getCellLocation"); + + // OP_COARSE_LOCATION controls both fine and coarse location. + if (mAppOps.noteOp(AppOpsManager.OP_COARSE_LOCATION, Binder.getCallingUid(), + callingPackage) != AppOpsManager.MODE_ALLOWED) { + log("getCellLocation: returning null; mode != allowed"); return null; } - if (DBG_LOC) log("getCellLocation: is active user"); - Bundle data = new Bundle(); - Phone phone = getPhone(mSubscriptionController.getDefaultDataSubId()); - if (phone == null) { + if (checkIfCallerIsSelfOrForegroundUser() || + checkCallerInteractAcrossUsersFull()) { + if (DBG_LOC) log("getCellLocation: is active user"); + Bundle data = new Bundle(); + Phone phone = getPhone(mSubscriptionController.getDefaultDataSubId()); + if (phone == null) { + return null; + } + + WorkSource workSource = getWorkSource(null, Binder.getCallingUid()); + phone.getCellLocation(workSource).fillInNotifierBundle(data); + return data; + } else { + log("getCellLocation: suppress non-active user"); return null; } + } - WorkSource workSource = getWorkSource(null, Binder.getCallingUid()); - phone.getCellLocation(workSource).fillInNotifierBundle(data); - return data; + private void enforceFineOrCoarseLocationPermission(String message) { + try { + mApp.enforceCallingOrSelfPermission( + android.Manifest.permission.ACCESS_FINE_LOCATION, null); + } catch (SecurityException e) { + // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION + // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this + // is the weaker precondition + mApp.enforceCallingOrSelfPermission( + android.Manifest.permission.ACCESS_COARSE_LOCATION, message); + } } + @Override public void enableLocationUpdates() { enableLocationUpdatesForSubscriber(getDefaultSubscription()); @@ -1677,8 +1703,11 @@ public class PhoneInterfaceManager extends ITelephony.Stub { @Override @SuppressWarnings("unchecked") public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) { - if (!LocationAccessPolicy.canAccessCellLocation(mPhone.getContext(), - callingPackage, Binder.getCallingUid())) { + enforceFineOrCoarseLocationPermission("getNeighboringCellInfo"); + + // OP_COARSE_LOCATION controls both fine and coarse location. + if (mAppOps.noteOp(AppOpsManager.OP_COARSE_LOCATION, Binder.getCallingUid(), + callingPackage) != AppOpsManager.MODE_ALLOWED) { return null; } @@ -1687,37 +1716,52 @@ public class PhoneInterfaceManager extends ITelephony.Stub { return null; } - if (DBG_LOC) log("getNeighboringCellInfo: is active user"); + if (checkIfCallerIsSelfOrForegroundUser() || + checkCallerInteractAcrossUsersFull()) { + if (DBG_LOC) log("getNeighboringCellInfo: is active user"); - ArrayList<NeighboringCellInfo> cells = null; + ArrayList<NeighboringCellInfo> cells = null; - WorkSource workSource = getWorkSource(null, Binder.getCallingUid()); - try { - cells = (ArrayList<NeighboringCellInfo>) sendRequest( - CMD_HANDLE_NEIGHBORING_CELL, workSource, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - } catch (RuntimeException e) { - Log.e(LOG_TAG, "getNeighboringCellInfo " + e); + WorkSource workSource = getWorkSource(null, Binder.getCallingUid()); + try { + cells = (ArrayList<NeighboringCellInfo>) sendRequest( + CMD_HANDLE_NEIGHBORING_CELL, workSource, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } catch (RuntimeException e) { + Log.e(LOG_TAG, "getNeighboringCellInfo " + e); + } + return cells; + } else { + if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user"); + return null; } - return cells; } @Override public List<CellInfo> getAllCellInfo(String callingPackage) { - if (!LocationAccessPolicy.canAccessCellLocation(mPhone.getContext(), - callingPackage, Binder.getCallingUid())) { + enforceFineOrCoarseLocationPermission("getAllCellInfo"); + + // OP_COARSE_LOCATION controls both fine and coarse location. + if (mAppOps.noteOp(AppOpsManager.OP_COARSE_LOCATION, Binder.getCallingUid(), + callingPackage) != AppOpsManager.MODE_ALLOWED) { return null; } - if (DBG_LOC) log("getAllCellInfo: is active user"); - WorkSource workSource = getWorkSource(null, Binder.getCallingUid()); - List<CellInfo> cellInfos = new ArrayList<CellInfo>(); - for (Phone phone : PhoneFactory.getPhones()) { - final List<CellInfo> info = phone.getAllCellInfo(workSource); - if (info != null) cellInfos.addAll(info); + if (checkIfCallerIsSelfOrForegroundUser() || + checkCallerInteractAcrossUsersFull()) { + if (DBG_LOC) log("getAllCellInfo: is active user"); + WorkSource workSource = getWorkSource(null, Binder.getCallingUid()); + List<CellInfo> cellInfos = new ArrayList<CellInfo>(); + for (Phone phone : PhoneFactory.getPhones()) { + final List<CellInfo> info = phone.getAllCellInfo(workSource); + if (info != null) cellInfos.addAll(info); + } + return cellInfos; + } else { + if (DBG_LOC) log("getAllCellInfo: suppress non-active user"); + return null; } - return cellInfos; } @Override @@ -1759,6 +1803,47 @@ public class PhoneInterfaceManager extends ITelephony.Stub { // /** + * Returns true if the caller holds INTERACT_ACROSS_USERS_FULL. + */ + private boolean checkCallerInteractAcrossUsersFull() { + return mPhone.getContext().checkCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) + == PackageManager.PERMISSION_GRANTED; + } + + private static boolean checkIfCallerIsSelfOrForegroundUser() { + boolean ok; + + boolean self = Binder.getCallingUid() == Process.myUid(); + if (!self) { + // Get the caller's user id then clear the calling identity + // which will be restored in the finally clause. + int callingUser = UserHandle.getCallingUserId(); + long ident = Binder.clearCallingIdentity(); + + try { + // With calling identity cleared the current user is the foreground user. + int foregroundUser = ActivityManager.getCurrentUser(); + ok = (foregroundUser == callingUser); + if (DBG_LOC) { + log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser + + " callingUser=" + callingUser + " ok=" + ok); + } + } catch (Exception ex) { + if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex); + ok = false; + } finally { + Binder.restoreCallingIdentity(ident); + } + } else { + if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self"); + ok = true; + } + if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok); + return ok; + } + + /** * Make sure the caller has the MODIFY_PHONE_STATE permission. * * @throws SecurityException if the caller does not have the required permission |
