Loading services/core/java/com/android/server/TelephonyRegistry.java +25 −71 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ import com.android.internal.telephony.ITelephonyRegistry; import com.android.internal.telephony.PhoneConstantConversions; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyPermissions; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.am.BatteryStatsService; Loading Loading @@ -384,21 +385,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { + " callback.asBinder=" + callback.asBinder()); } try { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, "addOnSubscriptionsChangedListener"); // SKIP checking for run-time permission since caller or self has PRIVILEGED permission } catch (SecurityException e) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PHONE_STATE, "addOnSubscriptionsChangedListener"); if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(), callingPackage) != AppOpsManager.MODE_ALLOWED) { if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState( mContext, callingPackage, "addOnSubscriptionsChangedListener")) { return; } } synchronized (mRecords) { Loading Loading @@ -493,22 +483,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events != PhoneStateListener.LISTEN_NONE) { /* Checks permission and throws Security exception */ checkListenerPermission(events); if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) { try { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null); // SKIP checking for run-time permission since caller or self has PRIVILEGED // permission } catch (SecurityException e) { if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(), callingPackage) != AppOpsManager.MODE_ALLOWED) { // Checks permission and throws SecurityException for disallowed operations. For pre-M // apps whose runtime permission has been revoked, we return immediately to skip sending // events to the app without crashing it. if (!checkListenerPermission(events, callingPackage, "listen")) { return; } } } int phoneId = SubscriptionManager.getPhoneId(subId); synchronized (mRecords) { Loading @@ -526,7 +506,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { r.callerPid = Binder.getCallingPid(); boolean isPhoneStateEvent = (events & (CHECK_PHONE_STATE_PERMISSION_MASK | ENFORCE_PHONE_STATE_PERMISSION_MASK)) != 0; r.canReadPhoneState = isPhoneStateEvent && canReadPhoneState(callingPackage); r.canReadPhoneState = isPhoneStateEvent && canReadPhoneState(callingPackage, "listen"); // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID, // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID if (!SubscriptionManager.isValidSubscriptionId(subId)) { Loading Loading @@ -686,21 +667,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } private boolean canReadPhoneState(String callingPackage) { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { // SKIP checking for run-time permission since caller or self has PRIVILEGED permission return true; } boolean canReadPhoneState = mContext.checkCallingOrSelfPermission( android.Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED; if (canReadPhoneState && mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(), callingPackage) != AppOpsManager.MODE_ALLOWED) { private boolean canReadPhoneState(String callingPackage, String message) { try { return TelephonyPermissions.checkCallingOrSelfReadPhoneState( mContext, callingPackage, message); } catch (SecurityException e) { return false; } return canReadPhoneState; } private String getCallIncomingNumber(Record record, int phoneId) { Loading Loading @@ -1676,7 +1649,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { return; } enforceCarrierPrivilege(); TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege( SubscriptionManager.getDefaultSubscriptionId(), method); } private boolean checkNotifyPermission(String method) { Loading @@ -1694,23 +1668,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { == PackageManager.PERMISSION_GRANTED; } private void enforceCarrierPrivilege() { TelephonyManager tm = TelephonyManager.getDefault(); String[] pkgs = mContext.getPackageManager().getPackagesForUid(Binder.getCallingUid()); for (String pkg : pkgs) { if (tm.checkCarrierPrivilegesForPackage(pkg) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { return; } } String msg = "Carrier Privilege Permission Denial: from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid(); if (DBG) log(msg); throw new SecurityException(msg); } private void checkListenerPermission(int events) { private boolean checkListenerPermission(int events, String callingPackage, String message) { if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.ACCESS_COARSE_LOCATION, null); Loading @@ -1724,22 +1682,18 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) { try { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null); // SKIP checking for run-time permission since caller or self has PRIVILEGED // permission } catch (SecurityException e) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PHONE_STATE, null); if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState( mContext, callingPackage, message)) { return false; } } if ((events & PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRECISE_PHONE_STATE, null); } return true; } private void handleRemoveListLocked() { Loading telephony/java/com/android/internal/telephony/ITelephony.aidl +5 −0 Original line number Diff line number Diff line Loading @@ -951,6 +951,11 @@ interface ITelephony { */ int getCarrierPrivilegeStatus(int subId); /** * Similar to above, but check for the given uid. */ int getCarrierPrivilegeStatusForUid(int subId, int uid); /** * Similar to above, but check for the package whose name is pkgName. */ Loading telephony/java/com/android/internal/telephony/TelephonyPermissions.java 0 → 100644 +209 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.internal.telephony; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; import android.os.Binder; import android.os.RemoteException; import android.os.ServiceManager; import android.telephony.Rlog; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ITelephony; /** Utility class for Telephony permission enforcement. */ public final class TelephonyPermissions { private static final String LOG_TAG = "TelephonyPermissions"; private static final boolean DBG = false; private TelephonyPermissions() {} /** * Check whether the caller (or self, if not processing an IPC) can read phone state. * * <p>This method behaves in one of the following ways: * <ul> * <li>return true: if the caller has either the READ_PRIVILEGED_PHONE_STATE permission or the * READ_PHONE_STATE runtime permission. * <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for * apps which support runtime permissions, if the caller does not currently have any of * these permissions. * <li>return false: if the caller lacks all of these permissions and doesn't support runtime * permissions. This implies that the user revoked the ability to read phone state * manually (via AppOps). In this case we can't throw as it would break app compatibility, * so we return false to indicate that the calling function should return dummy data. * </ul> */ public static boolean checkCallingOrSelfReadPhoneState( Context context, String callingPackage, String message) { return checkReadPhoneState(context, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, message); } /** * Check whether the app with the given pid/uid can read phone state. * * <p>This method behaves in one of the following ways: * <ul> * <li>return true: if the caller has either the READ_PRIVILEGED_PHONE_STATE permission or the * READ_PHONE_STATE runtime permission. * <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for * apps which support runtime permissions, if the caller does not currently have any of * these permissions. * <li>return false: if the caller lacks all of these permissions and doesn't support runtime * permissions. This implies that the user revoked the ability to read phone state * manually (via AppOps). In this case we can't throw as it would break app compatibility, * so we return false to indicate that the calling function should return dummy data. * </ul> */ public static boolean checkReadPhoneState( Context context, int pid, int uid, String callingPackage, String message) { try { context.enforcePermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message); // SKIP checking for run-time permission since caller has PRIVILEGED permission return true; } catch (SecurityException privilegedPhoneStateException) { context.enforcePermission( android.Manifest.permission.READ_PHONE_STATE, pid, uid, message); } // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been // revoked. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); return appOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, uid, callingPackage) == AppOpsManager.MODE_ALLOWED; } /** * Returns whether the caller can read phone numbers. * * <p>Besides apps with the ability to read phone state per {@link #checkReadPhoneState}, the * default SMS app and apps with READ_SMS or READ_PHONE_NUMBERS can also read phone numbers. */ public static boolean checkCallingOrSelfReadPhoneNumber( Context context, String callingPackage, String message) { return checkReadPhoneNumber( context, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, message); } @VisibleForTesting public static boolean checkReadPhoneNumber( Context context, int pid, int uid, String callingPackage, String message) { // Default SMS app can always read it. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); if (appOps.noteOp(AppOpsManager.OP_WRITE_SMS, uid, callingPackage) == AppOpsManager.MODE_ALLOWED) { return true; } // NOTE(b/73308711): If an app has one of the following AppOps bits explicitly revoked, they // will be denied access, even if they have another permission and AppOps bit if needed. // First, check if we can read the phone state. try { return checkReadPhoneState(context, pid, uid, callingPackage, message); } catch (SecurityException readPhoneStateSecurityException) { } // Can be read with READ_SMS too. try { context.enforcePermission(android.Manifest.permission.READ_SMS, pid, uid, message); int opCode = AppOpsManager.permissionToOpCode(android.Manifest.permission.READ_SMS); if (opCode != AppOpsManager.OP_NONE) { return appOps.noteOp(opCode, uid, callingPackage) == AppOpsManager.MODE_ALLOWED; } else { return true; } } catch (SecurityException readSmsSecurityException) { } // Can be read with READ_PHONE_NUMBERS too. try { context.enforcePermission(android.Manifest.permission.READ_PHONE_NUMBERS, pid, uid, message); int opCode = AppOpsManager.permissionToOpCode( android.Manifest.permission.READ_PHONE_NUMBERS); if (opCode != AppOpsManager.OP_NONE) { return appOps.noteOp(opCode, uid, callingPackage) == AppOpsManager.MODE_ALLOWED; } else { return true; } } catch (SecurityException readPhoneNumberSecurityException) { } throw new SecurityException(message + ": Neither user " + uid + " nor current process has " + android.Manifest.permission.READ_PHONE_STATE + ", " + android.Manifest.permission.READ_SMS + ", or " + android.Manifest.permission.READ_PHONE_NUMBERS); } /** * Ensure the caller (or self, if not processing an IPC) has MODIFY_PHONE_STATE (and is thus a * privileged app) or carrier privileges. * * @throws SecurityException if the caller does not have the required permission/privileges */ public static void enforceCallingOrSelfModifyPermissionOrCarrierPrivilege( Context context, int subId, String message) { if (context.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { return; } if (DBG) Rlog.d(LOG_TAG, "No modify permission, check carrier privilege next."); enforceCallingOrSelfCarrierPrivilege(subId, message); } /** * Make sure the caller (or self, if not processing an IPC) has carrier privileges. * * @throws SecurityException if the caller does not have the required privileges */ public static void enforceCallingOrSelfCarrierPrivilege(int subId, String message) { // NOTE: It's critical that we explicitly pass the calling UID here rather than call // TelephonyManager#hasCarrierPrivileges directly, as the latter only works when called from // the phone process. When called from another process, it will check whether that process // has carrier privileges instead. enforceCarrierPrivilege(subId, Binder.getCallingUid(), message); } private static void enforceCarrierPrivilege(int subId, int uid, String message) { if (getCarrierPrivilegeStatus(subId, uid) != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { if (DBG) Rlog.e(LOG_TAG, "No Carrier Privilege."); throw new SecurityException(message); } } private static int getCarrierPrivilegeStatus(int subId, int uid) { ITelephony telephony = ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE)); try { if (telephony != null) { return telephony.getCarrierPrivilegeStatusForUid(subId, uid); } } catch (RemoteException e) { // Fallback below. } Rlog.e(LOG_TAG, "Phone process is down, cannot check carrier privileges"); return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; } } Loading
services/core/java/com/android/server/TelephonyRegistry.java +25 −71 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ import com.android.internal.telephony.ITelephonyRegistry; import com.android.internal.telephony.PhoneConstantConversions; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyPermissions; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.am.BatteryStatsService; Loading Loading @@ -384,21 +385,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { + " callback.asBinder=" + callback.asBinder()); } try { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, "addOnSubscriptionsChangedListener"); // SKIP checking for run-time permission since caller or self has PRIVILEGED permission } catch (SecurityException e) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PHONE_STATE, "addOnSubscriptionsChangedListener"); if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(), callingPackage) != AppOpsManager.MODE_ALLOWED) { if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState( mContext, callingPackage, "addOnSubscriptionsChangedListener")) { return; } } synchronized (mRecords) { Loading Loading @@ -493,22 +483,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events != PhoneStateListener.LISTEN_NONE) { /* Checks permission and throws Security exception */ checkListenerPermission(events); if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) { try { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null); // SKIP checking for run-time permission since caller or self has PRIVILEGED // permission } catch (SecurityException e) { if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(), callingPackage) != AppOpsManager.MODE_ALLOWED) { // Checks permission and throws SecurityException for disallowed operations. For pre-M // apps whose runtime permission has been revoked, we return immediately to skip sending // events to the app without crashing it. if (!checkListenerPermission(events, callingPackage, "listen")) { return; } } } int phoneId = SubscriptionManager.getPhoneId(subId); synchronized (mRecords) { Loading @@ -526,7 +506,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { r.callerPid = Binder.getCallingPid(); boolean isPhoneStateEvent = (events & (CHECK_PHONE_STATE_PERMISSION_MASK | ENFORCE_PHONE_STATE_PERMISSION_MASK)) != 0; r.canReadPhoneState = isPhoneStateEvent && canReadPhoneState(callingPackage); r.canReadPhoneState = isPhoneStateEvent && canReadPhoneState(callingPackage, "listen"); // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID, // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID if (!SubscriptionManager.isValidSubscriptionId(subId)) { Loading Loading @@ -686,21 +667,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } private boolean canReadPhoneState(String callingPackage) { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { // SKIP checking for run-time permission since caller or self has PRIVILEGED permission return true; } boolean canReadPhoneState = mContext.checkCallingOrSelfPermission( android.Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED; if (canReadPhoneState && mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(), callingPackage) != AppOpsManager.MODE_ALLOWED) { private boolean canReadPhoneState(String callingPackage, String message) { try { return TelephonyPermissions.checkCallingOrSelfReadPhoneState( mContext, callingPackage, message); } catch (SecurityException e) { return false; } return canReadPhoneState; } private String getCallIncomingNumber(Record record, int phoneId) { Loading Loading @@ -1676,7 +1649,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { return; } enforceCarrierPrivilege(); TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege( SubscriptionManager.getDefaultSubscriptionId(), method); } private boolean checkNotifyPermission(String method) { Loading @@ -1694,23 +1668,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { == PackageManager.PERMISSION_GRANTED; } private void enforceCarrierPrivilege() { TelephonyManager tm = TelephonyManager.getDefault(); String[] pkgs = mContext.getPackageManager().getPackagesForUid(Binder.getCallingUid()); for (String pkg : pkgs) { if (tm.checkCarrierPrivilegesForPackage(pkg) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { return; } } String msg = "Carrier Privilege Permission Denial: from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid(); if (DBG) log(msg); throw new SecurityException(msg); } private void checkListenerPermission(int events) { private boolean checkListenerPermission(int events, String callingPackage, String message) { if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.ACCESS_COARSE_LOCATION, null); Loading @@ -1724,22 +1682,18 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) { try { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null); // SKIP checking for run-time permission since caller or self has PRIVILEGED // permission } catch (SecurityException e) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PHONE_STATE, null); if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState( mContext, callingPackage, message)) { return false; } } if ((events & PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRECISE_PHONE_STATE, null); } return true; } private void handleRemoveListLocked() { Loading
telephony/java/com/android/internal/telephony/ITelephony.aidl +5 −0 Original line number Diff line number Diff line Loading @@ -951,6 +951,11 @@ interface ITelephony { */ int getCarrierPrivilegeStatus(int subId); /** * Similar to above, but check for the given uid. */ int getCarrierPrivilegeStatusForUid(int subId, int uid); /** * Similar to above, but check for the package whose name is pkgName. */ Loading
telephony/java/com/android/internal/telephony/TelephonyPermissions.java 0 → 100644 +209 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.internal.telephony; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; import android.os.Binder; import android.os.RemoteException; import android.os.ServiceManager; import android.telephony.Rlog; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ITelephony; /** Utility class for Telephony permission enforcement. */ public final class TelephonyPermissions { private static final String LOG_TAG = "TelephonyPermissions"; private static final boolean DBG = false; private TelephonyPermissions() {} /** * Check whether the caller (or self, if not processing an IPC) can read phone state. * * <p>This method behaves in one of the following ways: * <ul> * <li>return true: if the caller has either the READ_PRIVILEGED_PHONE_STATE permission or the * READ_PHONE_STATE runtime permission. * <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for * apps which support runtime permissions, if the caller does not currently have any of * these permissions. * <li>return false: if the caller lacks all of these permissions and doesn't support runtime * permissions. This implies that the user revoked the ability to read phone state * manually (via AppOps). In this case we can't throw as it would break app compatibility, * so we return false to indicate that the calling function should return dummy data. * </ul> */ public static boolean checkCallingOrSelfReadPhoneState( Context context, String callingPackage, String message) { return checkReadPhoneState(context, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, message); } /** * Check whether the app with the given pid/uid can read phone state. * * <p>This method behaves in one of the following ways: * <ul> * <li>return true: if the caller has either the READ_PRIVILEGED_PHONE_STATE permission or the * READ_PHONE_STATE runtime permission. * <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for * apps which support runtime permissions, if the caller does not currently have any of * these permissions. * <li>return false: if the caller lacks all of these permissions and doesn't support runtime * permissions. This implies that the user revoked the ability to read phone state * manually (via AppOps). In this case we can't throw as it would break app compatibility, * so we return false to indicate that the calling function should return dummy data. * </ul> */ public static boolean checkReadPhoneState( Context context, int pid, int uid, String callingPackage, String message) { try { context.enforcePermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message); // SKIP checking for run-time permission since caller has PRIVILEGED permission return true; } catch (SecurityException privilegedPhoneStateException) { context.enforcePermission( android.Manifest.permission.READ_PHONE_STATE, pid, uid, message); } // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been // revoked. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); return appOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, uid, callingPackage) == AppOpsManager.MODE_ALLOWED; } /** * Returns whether the caller can read phone numbers. * * <p>Besides apps with the ability to read phone state per {@link #checkReadPhoneState}, the * default SMS app and apps with READ_SMS or READ_PHONE_NUMBERS can also read phone numbers. */ public static boolean checkCallingOrSelfReadPhoneNumber( Context context, String callingPackage, String message) { return checkReadPhoneNumber( context, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, message); } @VisibleForTesting public static boolean checkReadPhoneNumber( Context context, int pid, int uid, String callingPackage, String message) { // Default SMS app can always read it. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); if (appOps.noteOp(AppOpsManager.OP_WRITE_SMS, uid, callingPackage) == AppOpsManager.MODE_ALLOWED) { return true; } // NOTE(b/73308711): If an app has one of the following AppOps bits explicitly revoked, they // will be denied access, even if they have another permission and AppOps bit if needed. // First, check if we can read the phone state. try { return checkReadPhoneState(context, pid, uid, callingPackage, message); } catch (SecurityException readPhoneStateSecurityException) { } // Can be read with READ_SMS too. try { context.enforcePermission(android.Manifest.permission.READ_SMS, pid, uid, message); int opCode = AppOpsManager.permissionToOpCode(android.Manifest.permission.READ_SMS); if (opCode != AppOpsManager.OP_NONE) { return appOps.noteOp(opCode, uid, callingPackage) == AppOpsManager.MODE_ALLOWED; } else { return true; } } catch (SecurityException readSmsSecurityException) { } // Can be read with READ_PHONE_NUMBERS too. try { context.enforcePermission(android.Manifest.permission.READ_PHONE_NUMBERS, pid, uid, message); int opCode = AppOpsManager.permissionToOpCode( android.Manifest.permission.READ_PHONE_NUMBERS); if (opCode != AppOpsManager.OP_NONE) { return appOps.noteOp(opCode, uid, callingPackage) == AppOpsManager.MODE_ALLOWED; } else { return true; } } catch (SecurityException readPhoneNumberSecurityException) { } throw new SecurityException(message + ": Neither user " + uid + " nor current process has " + android.Manifest.permission.READ_PHONE_STATE + ", " + android.Manifest.permission.READ_SMS + ", or " + android.Manifest.permission.READ_PHONE_NUMBERS); } /** * Ensure the caller (or self, if not processing an IPC) has MODIFY_PHONE_STATE (and is thus a * privileged app) or carrier privileges. * * @throws SecurityException if the caller does not have the required permission/privileges */ public static void enforceCallingOrSelfModifyPermissionOrCarrierPrivilege( Context context, int subId, String message) { if (context.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { return; } if (DBG) Rlog.d(LOG_TAG, "No modify permission, check carrier privilege next."); enforceCallingOrSelfCarrierPrivilege(subId, message); } /** * Make sure the caller (or self, if not processing an IPC) has carrier privileges. * * @throws SecurityException if the caller does not have the required privileges */ public static void enforceCallingOrSelfCarrierPrivilege(int subId, String message) { // NOTE: It's critical that we explicitly pass the calling UID here rather than call // TelephonyManager#hasCarrierPrivileges directly, as the latter only works when called from // the phone process. When called from another process, it will check whether that process // has carrier privileges instead. enforceCarrierPrivilege(subId, Binder.getCallingUid(), message); } private static void enforceCarrierPrivilege(int subId, int uid, String message) { if (getCarrierPrivilegeStatus(subId, uid) != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { if (DBG) Rlog.e(LOG_TAG, "No Carrier Privilege."); throw new SecurityException(message); } } private static int getCarrierPrivilegeStatus(int subId, int uid) { ITelephony telephony = ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE)); try { if (telephony != null) { return telephony.getCarrierPrivilegeStatusForUid(subId, uid); } } catch (RemoteException e) { // Fallback below. } Rlog.e(LOG_TAG, "Phone process is down, cannot check carrier privileges"); return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; } }