diff options
4 files changed, 66 insertions, 118 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index dd51185d5d0c..ba1629c59dc3 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -9215,6 +9215,7 @@ package android.telephony { method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCarrierPrivilegeStatus(int); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPrivilegedPackagesForAllActiveSubscriptions(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(); diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 630554ddf72d..5f17e5e83b93 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -1293,7 +1293,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // only CarrierService with carrier privilege rule should have the permission int[] subIds = Arrays.stream(SubscriptionManager.from(mContext) .getActiveSubscriptionIdList(false)) - .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(i)).toArray(); + .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(mContext, + i)).toArray(); if (ArrayUtils.isEmpty(subIds)) { loge("notifyCarrierNetworkChange without carrier privilege"); // the active subId does not have carrier privilege. @@ -2301,7 +2302,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return; } - TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege( + TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext, SubscriptionManager.getDefaultSubscriptionId(), method); } diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java index 72ad4cd83d01..c8e2b8962072 100644 --- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java @@ -27,8 +27,6 @@ import android.content.pm.PackageManager; import android.os.Binder; import android.os.Build; import android.os.Process; -import android.os.RemoteException; -import android.os.ServiceManager; import android.os.UserHandle; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -41,7 +39,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.function.Supplier; /** Utility class for Telephony permission enforcement. */ public final class TelephonyPermissions { @@ -49,9 +46,6 @@ public final class TelephonyPermissions { private static final boolean DBG = false; - private static final Supplier<ITelephony> TELEPHONY_SUPPLIER = () -> - ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE)); - /** * Whether to disable the new device identifier access restrictions. */ @@ -137,49 +131,6 @@ public final class TelephonyPermissions { public static boolean checkReadPhoneState( Context context, int subId, int pid, int uid, String callingPackage, @Nullable String callingFeatureId, String message) { - return checkReadPhoneState( - context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, callingFeatureId, - message); - } - - /** - * Check whether the calling packages has carrier privileges for the passing subscription. - * @return {@code true} if the caller has carrier privileges, {@false} otherwise. - */ - public static boolean checkCarrierPrivilegeForSubId(int subId) { - if (SubscriptionManager.isValidSubscriptionId(subId) - && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, Binder.getCallingUid()) - == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { - return true; - } - return false; - } - - /** - * 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 the READ_PRIVILEGED_PHONE_STATE permission, the - * READ_PHONE_STATE runtime permission, or carrier privileges on the given subId. - * <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> - * - * <p>Note: for simplicity, this method always returns false for callers using legacy - * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged. - * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+ - * devices. - */ - @VisibleForTesting - public static boolean checkReadPhoneState( - Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid, - String callingPackage, @Nullable String callingFeatureId, String message) { try { context.enforcePermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message); @@ -194,7 +145,7 @@ public final class TelephonyPermissions { // If we don't have the runtime permission, but do have carrier privileges, that // suffices for reading phone state. if (SubscriptionManager.isValidSubscriptionId(subId)) { - enforceCarrierPrivilege(telephonySupplier, subId, uid, message); + enforceCarrierPrivilege(context, subId, uid, message); return true; } throw phoneStateException; @@ -209,23 +160,16 @@ public final class TelephonyPermissions { } /** - * Check whether the app with the given pid/uid can read phone state, or has carrier - * privileges on any active subscription. - * - * <p>If the app does not have carrier privilege, this method will return {@code false} instead - * of throwing a SecurityException. Therefore, the callers cannot tell the difference - * between M+ apps which declare the runtime permission but do not have it, and pre-M apps - * which declare the static permission but had access revoked via AppOps. Apps in the former - * category expect SecurityExceptions; apps in the latter don't. So this method is suitable for - * use only if the behavior in both scenarios is meant to be identical. - * - * @return {@code true} if the app can read phone state or has carrier privilege; - * {@code false} otherwise. + * Check whether the calling packages has carrier privileges for the passing subscription. + * @return {@code true} if the caller has carrier privileges, {@false} otherwise. */ - public static boolean checkReadPhoneStateOnAnyActiveSub(Context context, int pid, int uid, - String callingPackage, @Nullable String callingFeatureId, String message) { - return checkReadPhoneStateOnAnyActiveSub(context, TELEPHONY_SUPPLIER, pid, uid, - callingPackage, callingFeatureId, message); + public static boolean checkCarrierPrivilegeForSubId(Context context, int subId) { + if (SubscriptionManager.isValidSubscriptionId(subId) + && getCarrierPrivilegeStatus(context, subId, Binder.getCallingUid()) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { + return true; + } + return false; } /** @@ -242,9 +186,7 @@ public final class TelephonyPermissions { * @return {@code true} if the app can read phone state or has carrier privilege; * {@code false} otherwise. */ - @VisibleForTesting - public static boolean checkReadPhoneStateOnAnyActiveSub( - Context context, Supplier<ITelephony> telephonySupplier, int pid, int uid, + public static boolean checkReadPhoneStateOnAnyActiveSub(Context context, int pid, int uid, String callingPackage, @Nullable String callingFeatureId, String message) { try { context.enforcePermission( @@ -259,7 +201,7 @@ public final class TelephonyPermissions { } catch (SecurityException phoneStateException) { // If we don't have the runtime permission, but do have carrier privileges, that // suffices for reading phone state. - return checkCarrierPrivilegeForAnySubId(context, telephonySupplier, uid); + return checkCarrierPrivilegeForAnySubId(context, uid); } } @@ -374,12 +316,11 @@ public final class TelephonyPermissions { } // If the calling package has carrier privileges for specified sub, then allow access. - if (checkCarrierPrivilegeForSubId(subId)) return true; + if (checkCarrierPrivilegeForSubId(context, subId)) return true; // If the calling package has carrier privileges for any subscription // and allowCarrierPrivilegeOnAnySub is set true, then allow access. - if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId( - context, TELEPHONY_SUPPLIER, uid)) { + if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(context, uid)) { return true; } @@ -471,7 +412,7 @@ public final class TelephonyPermissions { uid) == PackageManager.PERMISSION_GRANTED) { return false; } - if (checkCarrierPrivilegeForSubId(subId)) { + if (checkCarrierPrivilegeForSubId(context, subId)) { return false; } } @@ -487,26 +428,12 @@ public final class TelephonyPermissions { public static boolean checkReadCallLog( Context context, int subId, int pid, int uid, String callingPackage, @Nullable String callingPackageName) { - return checkReadCallLog( - context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, callingPackageName); - } - - /** - * Check whether the app with the given pid/uid can read the call log. - * @return {@code true} if the specified app has the read call log permission and AppOpp granted - * to it, {@code false} otherwise. - */ - @VisibleForTesting - public static boolean checkReadCallLog( - Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid, - String callingPackage, @Nullable String callingFeatureId) { - if (context.checkPermission(Manifest.permission.READ_CALL_LOG, pid, uid) != PERMISSION_GRANTED) { // If we don't have the runtime permission, but do have carrier privileges, that // suffices for being able to see the call phone numbers. if (SubscriptionManager.isValidSubscriptionId(subId)) { - enforceCarrierPrivilege(telephonySupplier, subId, uid, "readCallLog"); + enforceCarrierPrivilege(context, subId, uid, "readCallLog"); return true; } return false; @@ -529,7 +456,7 @@ public final class TelephonyPermissions { Context context, int subId, String callingPackage, @Nullable String callingFeatureId, String message) { return checkReadPhoneNumber( - context, TELEPHONY_SUPPLIER, subId, Binder.getCallingPid(), Binder.getCallingUid(), + context, subId, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId, message); } @@ -541,7 +468,7 @@ public final class TelephonyPermissions { */ @VisibleForTesting public static boolean checkReadPhoneNumber( - Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid, + Context context, int subId, int pid, int uid, String callingPackage, @Nullable String callingFeatureId, String message) { // Default SMS app can always read it. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); @@ -556,7 +483,7 @@ public final class TelephonyPermissions { // First, check if we can read the phone state. try { return checkReadPhoneState( - context, telephonySupplier, subId, pid, uid, callingPackage, callingFeatureId, + context, subId, pid, uid, callingPackage, callingFeatureId, message); } catch (SecurityException readPhoneStateSecurityException) { } @@ -598,7 +525,7 @@ public final class TelephonyPermissions { } if (DBG) Log.d(LOG_TAG, "No modify permission, check carrier privilege next."); - enforceCallingOrSelfCarrierPrivilege(subId, message); + enforceCallingOrSelfCarrierPrivilege(context, subId, message); } /** @@ -618,7 +545,7 @@ public final class TelephonyPermissions { Log.d(LOG_TAG, "No READ_PHONE_STATE permission, check carrier privilege next."); } - enforceCallingOrSelfCarrierPrivilege(subId, message); + enforceCallingOrSelfCarrierPrivilege(context, subId, message); } /** @@ -639,7 +566,7 @@ public final class TelephonyPermissions { + "check carrier privilege next."); } - enforceCallingOrSelfCarrierPrivilege(subId, message); + enforceCallingOrSelfCarrierPrivilege(context, subId, message); } /** @@ -647,21 +574,18 @@ public final class TelephonyPermissions { * * @throws SecurityException if the caller does not have the required privileges */ - public static void enforceCallingOrSelfCarrierPrivilege(int subId, String message) { + public static void enforceCallingOrSelfCarrierPrivilege( + Context context, 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) { - enforceCarrierPrivilege(TELEPHONY_SUPPLIER, subId, uid, message); + enforceCarrierPrivilege(context, subId, Binder.getCallingUid(), message); } private static void enforceCarrierPrivilege( - Supplier<ITelephony> telephonySupplier, int subId, int uid, String message) { - if (getCarrierPrivilegeStatus(telephonySupplier, subId, uid) + Context context, int subId, int uid, String message) { + if (getCarrierPrivilegeStatus(context, subId, uid) != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { if (DBG) Log.e(LOG_TAG, "No Carrier Privilege."); throw new SecurityException(message); @@ -669,13 +593,12 @@ public final class TelephonyPermissions { } /** Returns whether the provided uid has carrier privileges for any active subscription ID. */ - private static boolean checkCarrierPrivilegeForAnySubId( - Context context, Supplier<ITelephony> telephonySupplier, int uid) { + private static boolean checkCarrierPrivilegeForAnySubId(Context context, int uid) { SubscriptionManager sm = (SubscriptionManager) context.getSystemService( Context.TELEPHONY_SUBSCRIPTION_SERVICE); int[] activeSubIds = sm.getActiveSubscriptionIdList(/* visibleOnly */ false); for (int activeSubId : activeSubIds) { - if (getCarrierPrivilegeStatus(telephonySupplier, activeSubId, uid) + if (getCarrierPrivilegeStatus(context, activeSubId, uid) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { return true; } @@ -683,18 +606,15 @@ public final class TelephonyPermissions { return false; } - private static int getCarrierPrivilegeStatus( - Supplier<ITelephony> telephonySupplier, int subId, int uid) { - ITelephony telephony = telephonySupplier.get(); + private static int getCarrierPrivilegeStatus(Context context, int subId, int uid) { + final long identity = Binder.clearCallingIdentity(); try { - if (telephony != null) { - return telephony.getCarrierPrivilegeStatusForUid(subId, uid); - } - } catch (RemoteException e) { - // Fallback below. + TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService( + Context.TELEPHONY_SERVICE); + return telephonyManager.createForSubscriptionId(subId).getCarrierPrivilegeStatus(uid); + } finally { + Binder.restoreCallingIdentity(identity); } - Log.e(LOG_TAG, "Phone process is down, cannot check carrier privileges"); - return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; } /** diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 55cf22ac1c32..32dfef75d70b 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -11750,6 +11750,32 @@ public class TelephonyManager { } /** + * Get the calling application status about carrier privileges for the subscription created + * in TelephonyManager. Used by Telephony Module for permission checking. + * + * @param uid Uid to check. + * @return any value of {@link #CARRIER_PRIVILEGE_STATUS_HAS_ACCESS}, + * {@link #CARRIER_PRIVILEGE_STATUS_NO_ACCESS}, + * {@link #CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED}, or + * {@link #CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES} + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public int getCarrierPrivilegeStatus(int uid) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.getCarrierPrivilegeStatusForUid(getSubId(), uid); + } + } catch (RemoteException ex) { + Log.e(TAG, "getCarrierPrivilegeStatus RemoteException", ex); + } + return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; + } + + /** * Returns a list of APNs set as overrides by the device policy manager via * {@link #addDevicePolicyOverrideApn}. * This method must only be called from the system or phone processes. |