1 /* 2 * Copyright (C) 2022 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.server.connectivity; 18 19 import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; 20 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 21 22 import android.annotation.NonNull; 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.content.pm.ApplicationInfo; 28 import android.content.pm.PackageManager; 29 import android.net.NetworkCapabilities; 30 import android.net.NetworkSpecifier; 31 import android.net.TelephonyNetworkSpecifier; 32 import android.os.Handler; 33 import android.os.HandlerThread; 34 import android.os.Process; 35 import android.telephony.SubscriptionManager; 36 import android.telephony.TelephonyManager; 37 import android.util.Log; 38 39 import com.android.internal.annotations.GuardedBy; 40 import com.android.internal.annotations.VisibleForTesting; 41 import com.android.modules.utils.HandlerExecutor; 42 import com.android.networkstack.apishim.TelephonyManagerShimImpl; 43 import com.android.networkstack.apishim.common.TelephonyManagerShim; 44 import com.android.networkstack.apishim.common.TelephonyManagerShim.CarrierPrivilegesListenerShim; 45 import com.android.networkstack.apishim.common.UnsupportedApiLevelException; 46 47 import java.util.ArrayList; 48 import java.util.List; 49 import java.util.concurrent.Executor; 50 51 /** 52 * Tracks the uid of the carrier privileged app that provides the carrier config. 53 * Authenticates if the caller has same uid as 54 * carrier privileged app that provides the carrier config 55 * @hide 56 */ 57 public class CarrierPrivilegeAuthenticator extends BroadcastReceiver { 58 private static final String TAG = CarrierPrivilegeAuthenticator.class.getSimpleName(); 59 private static final boolean DBG = true; 60 61 // The context is for the current user (system server) 62 private final Context mContext; 63 private final TelephonyManagerShim mTelephonyManagerShim; 64 private final TelephonyManager mTelephonyManager; 65 @GuardedBy("mLock") 66 private int[] mCarrierServiceUid; 67 @GuardedBy("mLock") 68 private int mModemCount = 0; 69 private final Object mLock = new Object(); 70 private final HandlerThread mThread; 71 private final Handler mHandler; 72 @NonNull 73 private final List<CarrierPrivilegesListenerShim> mCarrierPrivilegesChangedListeners = 74 new ArrayList<>(); 75 CarrierPrivilegeAuthenticator(@onNull final Context c, @NonNull final TelephonyManager t, @NonNull final TelephonyManagerShimImpl telephonyManagerShim)76 public CarrierPrivilegeAuthenticator(@NonNull final Context c, 77 @NonNull final TelephonyManager t, 78 @NonNull final TelephonyManagerShimImpl telephonyManagerShim) { 79 mContext = c; 80 mTelephonyManager = t; 81 mTelephonyManagerShim = telephonyManagerShim; 82 mThread = new HandlerThread(TAG); 83 mThread.start(); 84 mHandler = new Handler(mThread.getLooper()) {}; 85 synchronized (mLock) { 86 mModemCount = mTelephonyManager.getActiveModemCount(); 87 registerForCarrierChanges(); 88 updateCarrierServiceUid(); 89 } 90 } 91 CarrierPrivilegeAuthenticator(@onNull final Context c, @NonNull final TelephonyManager t)92 public CarrierPrivilegeAuthenticator(@NonNull final Context c, 93 @NonNull final TelephonyManager t) { 94 mContext = c; 95 mTelephonyManager = t; 96 mTelephonyManagerShim = TelephonyManagerShimImpl.newInstance(mTelephonyManager); 97 mThread = new HandlerThread(TAG); 98 mThread.start(); 99 mHandler = new Handler(mThread.getLooper()) {}; 100 synchronized (mLock) { 101 mModemCount = mTelephonyManager.getActiveModemCount(); 102 registerForCarrierChanges(); 103 updateCarrierServiceUid(); 104 } 105 } 106 107 /** 108 * Broadcast receiver for ACTION_MULTI_SIM_CONFIG_CHANGED 109 * 110 * <p>The broadcast receiver is registered with mHandler 111 */ 112 @Override onReceive(Context context, Intent intent)113 public void onReceive(Context context, Intent intent) { 114 switch (intent.getAction()) { 115 case TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED: 116 handleActionMultiSimConfigChanged(context, intent); 117 break; 118 default: 119 Log.d(TAG, "Unknown intent received with action: " + intent.getAction()); 120 } 121 } 122 handleActionMultiSimConfigChanged(Context context, Intent intent)123 private void handleActionMultiSimConfigChanged(Context context, Intent intent) { 124 unregisterCarrierPrivilegesListeners(); 125 synchronized (mLock) { 126 mModemCount = mTelephonyManager.getActiveModemCount(); 127 } 128 registerCarrierPrivilegesListeners(); 129 updateCarrierServiceUid(); 130 } 131 registerForCarrierChanges()132 private void registerForCarrierChanges() { 133 final IntentFilter filter = new IntentFilter(); 134 filter.addAction(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED); 135 mContext.registerReceiver(this, filter, null, mHandler); 136 registerCarrierPrivilegesListeners(); 137 } 138 registerCarrierPrivilegesListeners()139 private void registerCarrierPrivilegesListeners() { 140 final HandlerExecutor executor = new HandlerExecutor(mHandler); 141 int modemCount; 142 synchronized (mLock) { 143 modemCount = mModemCount; 144 } 145 try { 146 for (int i = 0; i < modemCount; i++) { 147 CarrierPrivilegesListenerShim carrierPrivilegesListener = 148 new CarrierPrivilegesListenerShim() { 149 @Override 150 public void onCarrierPrivilegesChanged( 151 @NonNull List<String> privilegedPackageNames, 152 @NonNull int[] privilegedUids) { 153 // Re-trigger the synchronous check (which is also very cheap due 154 // to caching in CarrierPrivilegesTracker). This allows consistency 155 // with the onSubscriptionsChangedListener and broadcasts. 156 updateCarrierServiceUid(); 157 } 158 }; 159 addCarrierPrivilegesListener(i, executor, carrierPrivilegesListener); 160 mCarrierPrivilegesChangedListeners.add(carrierPrivilegesListener); 161 } 162 } catch (IllegalArgumentException e) { 163 Log.e(TAG, "Encountered exception registering carrier privileges listeners", e); 164 } 165 } 166 addCarrierPrivilegesListener(int logicalSlotIndex, Executor executor, CarrierPrivilegesListenerShim listener)167 private void addCarrierPrivilegesListener(int logicalSlotIndex, Executor executor, 168 CarrierPrivilegesListenerShim listener) { 169 try { 170 mTelephonyManagerShim.addCarrierPrivilegesListener( 171 logicalSlotIndex, executor, listener); 172 } catch (UnsupportedApiLevelException unsupportedApiLevelException) { 173 // Should not happen since CarrierPrivilegeAuthenticator is only used on T+ 174 Log.e(TAG, "addCarrierPrivilegesListener API is not available"); 175 } 176 } 177 removeCarrierPrivilegesListener(CarrierPrivilegesListenerShim listener)178 private void removeCarrierPrivilegesListener(CarrierPrivilegesListenerShim listener) { 179 try { 180 mTelephonyManagerShim.removeCarrierPrivilegesListener(listener); 181 } catch (UnsupportedApiLevelException unsupportedApiLevelException) { 182 // Should not happen since CarrierPrivilegeAuthenticator is only used on T+ 183 Log.e(TAG, "removeCarrierPrivilegesListener API is not available"); 184 } 185 } 186 getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex)187 private String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex) { 188 try { 189 return mTelephonyManagerShim.getCarrierServicePackageNameForLogicalSlot( 190 logicalSlotIndex); 191 } catch (UnsupportedApiLevelException unsupportedApiLevelException) { 192 // Should not happen since CarrierPrivilegeAuthenticator is only used on T+ 193 Log.e(TAG, "getCarrierServicePackageNameForLogicalSlot API is not available"); 194 } 195 return null; 196 } 197 unregisterCarrierPrivilegesListeners()198 private void unregisterCarrierPrivilegesListeners() { 199 for (CarrierPrivilegesListenerShim carrierPrivilegesListener : 200 mCarrierPrivilegesChangedListeners) { 201 removeCarrierPrivilegesListener(carrierPrivilegesListener); 202 } 203 mCarrierPrivilegesChangedListeners.clear(); 204 } 205 206 /** 207 * Check if a UID is the carrier service app of the subscription ID in the provided capabilities 208 * 209 * This returns whether the passed UID is the carrier service package for the subscription ID 210 * stored in the telephony network specifier in the passed network capabilities. 211 * If the capabilities don't code for a cellular network, or if they don't have the 212 * subscription ID in their specifier, this returns false. 213 * 214 * This method can be used to check that a network request for {@link NET_CAPABILITY_CBS} is 215 * allowed for the UID of a caller, which must hold carrier privilege and provide the carrier 216 * config. 217 * It can also be used to check that a factory is entitled to grant access to a given network 218 * to a given UID on grounds that it is the carrier service package. 219 * 220 * @param callingUid uid of the app claimed to be the carrier service package. 221 * @param networkCapabilities the network capabilities for which carrier privilege is checked. 222 * @return true if uid provides the relevant carrier config else false. 223 */ hasCarrierPrivilegeForNetworkCapabilities(int callingUid, @NonNull NetworkCapabilities networkCapabilities)224 public boolean hasCarrierPrivilegeForNetworkCapabilities(int callingUid, 225 @NonNull NetworkCapabilities networkCapabilities) { 226 if (callingUid == Process.INVALID_UID) return false; 227 if (!networkCapabilities.hasSingleTransport(TRANSPORT_CELLULAR)) return false; 228 final int subId = getSubIdFromNetworkSpecifier(networkCapabilities.getNetworkSpecifier()); 229 if (SubscriptionManager.INVALID_SUBSCRIPTION_ID == subId) return false; 230 return callingUid == getCarrierServiceUidForSubId(subId); 231 } 232 233 @VisibleForTesting updateCarrierServiceUid()234 void updateCarrierServiceUid() { 235 synchronized (mLock) { 236 mCarrierServiceUid = new int[mModemCount]; 237 for (int i = 0; i < mModemCount; i++) { 238 mCarrierServiceUid[i] = getCarrierServicePackageUidForSlot(i); 239 } 240 } 241 } 242 243 @VisibleForTesting getCarrierServiceUidForSubId(int subId)244 int getCarrierServiceUidForSubId(int subId) { 245 final int slotId = getSlotIndex(subId); 246 synchronized (mLock) { 247 if (slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX && slotId < mModemCount) { 248 return mCarrierServiceUid[slotId]; 249 } 250 } 251 return Process.INVALID_UID; 252 } 253 254 @VisibleForTesting getSlotIndex(int subId)255 protected int getSlotIndex(int subId) { 256 return SubscriptionManager.getSlotIndex(subId); 257 } 258 259 @VisibleForTesting getSubIdFromNetworkSpecifier(NetworkSpecifier specifier)260 int getSubIdFromNetworkSpecifier(NetworkSpecifier specifier) { 261 if (specifier instanceof TelephonyNetworkSpecifier) { 262 return ((TelephonyNetworkSpecifier) specifier).getSubscriptionId(); 263 } 264 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 265 } 266 267 @VisibleForTesting getUidForPackage(String pkgName)268 int getUidForPackage(String pkgName) { 269 if (pkgName == null) { 270 return Process.INVALID_UID; 271 } 272 try { 273 PackageManager pm = mContext.getPackageManager(); 274 if (pm != null) { 275 ApplicationInfo applicationInfo = pm.getApplicationInfo(pkgName, 0); 276 if (applicationInfo != null) { 277 return applicationInfo.uid; 278 } 279 } 280 } catch (PackageManager.NameNotFoundException exception) { 281 // Didn't find package. Try other users 282 Log.i(TAG, "Unable to find uid for package " + pkgName); 283 } 284 return Process.INVALID_UID; 285 } 286 287 @VisibleForTesting getCarrierServicePackageUidForSlot(int slotId)288 int getCarrierServicePackageUidForSlot(int slotId) { 289 return getUidForPackage(getCarrierServicePackageNameForLogicalSlot(slotId)); 290 } 291 } 292