1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony; 18 19 import android.Manifest; 20 import android.app.AppOpsManager; 21 import android.compat.annotation.UnsupportedAppUsage; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.os.Binder; 25 import android.os.Build; 26 import android.os.UserHandle; 27 import android.service.carrier.CarrierMessagingService; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 import com.android.internal.telephony.util.TelephonyUtils; 31 import com.android.telephony.Rlog; 32 33 /** 34 * Permissions checks for SMS functionality 35 */ 36 public class SmsPermissions { 37 static final String LOG_TAG = "SmsPermissions"; 38 39 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 40 private final Phone mPhone; 41 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 42 private final Context mContext; 43 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 44 private final AppOpsManager mAppOps; 45 SmsPermissions(Phone phone, Context context, AppOpsManager appOps)46 public SmsPermissions(Phone phone, Context context, AppOpsManager appOps) { 47 mPhone = phone; 48 mContext = context; 49 mAppOps = appOps; 50 } 51 52 /** 53 * Check that the caller can send text messages. 54 * 55 * For persisted messages, the caller just needs the SEND_SMS permission. For unpersisted 56 * messages, the caller must either be the IMS app or a carrier-privileged app, or they must 57 * have both the MODIFY_PHONE_STATE and SEND_SMS permissions. 58 * 59 * @throws SecurityException if the caller is missing all necessary permission declaration or 60 * has had a necessary runtime permission revoked. 61 * @return true unless the caller has all necessary permissions but has a revoked AppOps bit. 62 */ checkCallingCanSendText( boolean persistMessageForNonDefaultSmsApp, String callingPackage, String callingAttributionTag, String message)63 public boolean checkCallingCanSendText( 64 boolean persistMessageForNonDefaultSmsApp, String callingPackage, 65 String callingAttributionTag, String message) { 66 // TODO(b/75978989): Should we allow IMS/carrier apps for persisted messages as well? 67 if (!persistMessageForNonDefaultSmsApp) { 68 try { 69 enforceCallerIsImsAppOrCarrierApp(message); 70 // No need to also check SEND_SMS. 71 return true; 72 } catch (SecurityException e) { 73 mContext.enforceCallingPermission( 74 android.Manifest.permission.MODIFY_PHONE_STATE, message); 75 } 76 } 77 return checkCallingCanSendSms(callingPackage, callingAttributionTag, message); 78 } 79 80 /** 81 * Enforces that the caller is one of the following apps: 82 * <ul> 83 * <li> IMS App determined by telephony to implement RCS features 84 * <li> Carrier App 85 * </ul> 86 */ enforceCallerIsImsAppOrCarrierApp(String message)87 public void enforceCallerIsImsAppOrCarrierApp(String message) { 88 String imsRcsPackage = CarrierSmsUtils.getImsRcsPackageForIntent(mContext, 89 mPhone, new Intent(CarrierMessagingService.SERVICE_INTERFACE)); 90 if (imsRcsPackage != null && packageNameMatchesCallingUid(imsRcsPackage)) { 91 return; 92 } 93 TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege( 94 mContext, mPhone.getSubId(), message); 95 } 96 97 /** 98 * Check that the caller has SEND_SMS permissions. Can only be called during an IPC. 99 * 100 * @throws SecurityException if the caller is missing the permission declaration or has had the 101 * permission revoked at runtime. 102 * @return whether the caller has the OP_SEND_SMS AppOps bit. 103 */ checkCallingCanSendSms(String callingPackage, String callingAttributionTag, String message)104 public boolean checkCallingCanSendSms(String callingPackage, String callingAttributionTag, 105 String message) { 106 mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, message); 107 return mAppOps.noteOp(AppOpsManager.OPSTR_SEND_SMS, Binder.getCallingUid(), callingPackage, 108 callingAttributionTag, null) == AppOpsManager.MODE_ALLOWED; 109 } 110 111 /** 112 * Check that the caller (or self, if this is not an IPC) has SEND_SMS permissions. 113 * 114 * @throws SecurityException if the caller is missing the permission declaration or has had the 115 * permission revoked at runtime. 116 * @return whether the caller has the OP_SEND_SMS AppOps bit. 117 */ checkCallingOrSelfCanSendSms(String callingPackage, String callingAttributionTag, String message)118 public boolean checkCallingOrSelfCanSendSms(String callingPackage, String callingAttributionTag, 119 String message) { 120 mContext.enforceCallingOrSelfPermission(Manifest.permission.SEND_SMS, message); 121 return mAppOps.noteOp(AppOpsManager.OPSTR_SEND_SMS, Binder.getCallingUid(), callingPackage, 122 callingAttributionTag, null) 123 == AppOpsManager.MODE_ALLOWED; 124 } 125 126 /** 127 * Check that the caller (or self, if this is not an IPC) can get SMSC address from (U)SIM. 128 * 129 * The default SMS application can get SMSC address, otherwise the caller must have 130 * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or carrier privileges. 131 * 132 * @return true if the caller is default SMS app or has the required permission and privileges. 133 * Otherwise, false; 134 */ checkCallingOrSelfCanGetSmscAddress(String callingPackage, String message)135 public boolean checkCallingOrSelfCanGetSmscAddress(String callingPackage, String message) { 136 // Allow it to the default SMS app always. 137 boolean isDefaultSmsPackage; 138 int callerUid = Binder.getCallingUid(); 139 final long identity = Binder.clearCallingIdentity(); 140 try { 141 isDefaultSmsPackage = isCallerDefaultSmsPackage(callingPackage, callerUid); 142 } finally { 143 Binder.restoreCallingIdentity(identity); 144 } 145 if (!isDefaultSmsPackage) { 146 Rlog.d(LOG_TAG, "Caller is not a default SMS application"); 147 TelephonyPermissions. 148 enforceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege( 149 mContext, mPhone.getSubId(), message); 150 } 151 return true; 152 } 153 154 /** 155 * Check that the caller (or self, if this is not an IPC) can set SMSC address on (U)SIM. 156 * 157 * The default SMS application can set SMSC address, otherwise the caller must have 158 * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier privileges. 159 * 160 * @return true if the caller is default SMS app or has the required permission and privileges. 161 * Otherwise, false. 162 */ checkCallingOrSelfCanSetSmscAddress(String callingPackage, String message)163 public boolean checkCallingOrSelfCanSetSmscAddress(String callingPackage, String message) { 164 // Allow it to the default SMS app always. 165 boolean isDefaultSmsPackage; 166 int callerUid = Binder.getCallingUid(); 167 final long identity = Binder.clearCallingIdentity(); 168 try { 169 isDefaultSmsPackage = isCallerDefaultSmsPackage(callingPackage, callerUid); 170 } finally { 171 Binder.restoreCallingIdentity(identity); 172 } 173 if (!isDefaultSmsPackage) { 174 Rlog.d(LOG_TAG, "Caller is not a default SMS application"); 175 // Allow it with MODIFY_PHONE_STATE or Carrier Privileges 176 TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mContext, 177 mPhone.getSubId(), message); 178 } 179 return true; 180 } 181 182 /** Check if a package is default SMS app. */ 183 @VisibleForTesting isCallerDefaultSmsPackage(String packageName, int callerUid)184 public boolean isCallerDefaultSmsPackage(String packageName, int callerUid) { 185 if (packageNameMatchesCallingUid(packageName, callerUid)) { 186 UserHandle userHandle = TelephonyUtils.getSubscriptionUserHandle(mContext, 187 mPhone.getSubId()); 188 return SmsApplication.isDefaultSmsApplicationAsUser(mContext, packageName, userHandle); 189 } 190 return false; 191 } 192 193 @VisibleForTesting packageNameMatchesCallingUid(String packageName)194 public boolean packageNameMatchesCallingUid(String packageName) { 195 return packageNameMatchesCallingUid(packageName, Binder.getCallingUid()); 196 } 197 198 /** 199 * Check if the passed in packageName belongs to the calling uid. 200 * @param packageName name of the package to check 201 * @return true if package belongs to calling uid, false otherwise 202 */ 203 @VisibleForTesting packageNameMatchesCallingUid(String packageName, int callerUid)204 public boolean packageNameMatchesCallingUid(String packageName, int callerUid) { 205 try { 206 ((AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE)) 207 .checkPackage(callerUid, packageName); 208 // If checkPackage doesn't throw an exception then we are the given package 209 return true; 210 } catch (SecurityException e) { 211 return false; 212 } 213 } 214 215 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) log(String msg)216 protected void log(String msg) { 217 Rlog.d(LOG_TAG, msg); 218 } 219 loge(String msg)220 protected void loge(String msg) { 221 Rlog.e(LOG_TAG, msg); 222 } 223 loge(String msg, Throwable e)224 protected void loge(String msg, Throwable e) { 225 Rlog.e(LOG_TAG, msg, e); 226 } 227 } 228