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.networkstack.apishim.TelephonyManagerShimImpl; 42 import com.android.networkstack.apishim.common.TelephonyManagerShim; 43 import com.android.networkstack.apishim.common.TelephonyManagerShim.CarrierPrivilegesListenerShim; 44 import com.android.networkstack.apishim.common.UnsupportedApiLevelException; 45 46 import java.util.ArrayList; 47 import java.util.List; 48 import java.util.concurrent.Executor; 49 import java.util.concurrent.RejectedExecutionException; 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 * An adapter {@link Executor} that posts all executed tasks onto the given 109 * {@link Handler}. 110 * 111 * TODO : migrate to the version in frameworks/libs/net when it's ready 112 * 113 * @hide 114 */ 115 public class HandlerExecutor implements Executor { 116 private final Handler mHandler; HandlerExecutor(@onNull Handler handler)117 public HandlerExecutor(@NonNull Handler handler) { 118 mHandler = handler; 119 } 120 @Override execute(Runnable command)121 public void execute(Runnable command) { 122 if (!mHandler.post(command)) { 123 throw new RejectedExecutionException(mHandler + " is shutting down"); 124 } 125 } 126 } 127 128 /** 129 * Broadcast receiver for ACTION_MULTI_SIM_CONFIG_CHANGED 130 * 131 * <p>The broadcast receiver is registered with mHandler 132 */ 133 @Override onReceive(Context context, Intent intent)134 public void onReceive(Context context, Intent intent) { 135 switch (intent.getAction()) { 136 case TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED: 137 handleActionMultiSimConfigChanged(context, intent); 138 break; 139 default: 140 Log.d(TAG, "Unknown intent received with action: " + intent.getAction()); 141 } 142 } 143 handleActionMultiSimConfigChanged(Context context, Intent intent)144 private void handleActionMultiSimConfigChanged(Context context, Intent intent) { 145 unregisterCarrierPrivilegesListeners(); 146 synchronized (mLock) { 147 mModemCount = mTelephonyManager.getActiveModemCount(); 148 } 149 registerCarrierPrivilegesListeners(); 150 updateCarrierServiceUid(); 151 } 152 registerForCarrierChanges()153 private void registerForCarrierChanges() { 154 final IntentFilter filter = new IntentFilter(); 155 filter.addAction(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED); 156 mContext.registerReceiver(this, filter, null, mHandler); 157 registerCarrierPrivilegesListeners(); 158 } 159 registerCarrierPrivilegesListeners()160 private void registerCarrierPrivilegesListeners() { 161 final HandlerExecutor executor = new HandlerExecutor(mHandler); 162 int modemCount; 163 synchronized (mLock) { 164 modemCount = mModemCount; 165 } 166 try { 167 for (int i = 0; i < modemCount; i++) { 168 CarrierPrivilegesListenerShim carrierPrivilegesListener = 169 new CarrierPrivilegesListenerShim() { 170 @Override 171 public void onCarrierPrivilegesChanged( 172 @NonNull List<String> privilegedPackageNames, 173 @NonNull int[] privilegedUids) { 174 // Re-trigger the synchronous check (which is also very cheap due 175 // to caching in CarrierPrivilegesTracker). This allows consistency 176 // with the onSubscriptionsChangedListener and broadcasts. 177 updateCarrierServiceUid(); 178 } 179 }; 180 addCarrierPrivilegesListener(i, executor, carrierPrivilegesListener); 181 mCarrierPrivilegesChangedListeners.add(carrierPrivilegesListener); 182 } 183 } catch (IllegalArgumentException e) { 184 Log.e(TAG, "Encountered exception registering carrier privileges listeners", e); 185 } 186 } 187 addCarrierPrivilegesListener(int logicalSlotIndex, Executor executor, CarrierPrivilegesListenerShim listener)188 private void addCarrierPrivilegesListener(int logicalSlotIndex, Executor executor, 189 CarrierPrivilegesListenerShim listener) { 190 try { 191 mTelephonyManagerShim.addCarrierPrivilegesListener( 192 logicalSlotIndex, executor, listener); 193 } catch (UnsupportedApiLevelException unsupportedApiLevelException) { 194 // Should not happen since CarrierPrivilegeAuthenticator is only used on T+ 195 Log.e(TAG, "addCarrierPrivilegesListener API is not available"); 196 } 197 } 198 removeCarrierPrivilegesListener(CarrierPrivilegesListenerShim listener)199 private void removeCarrierPrivilegesListener(CarrierPrivilegesListenerShim listener) { 200 try { 201 mTelephonyManagerShim.removeCarrierPrivilegesListener(listener); 202 } catch (UnsupportedApiLevelException unsupportedApiLevelException) { 203 // Should not happen since CarrierPrivilegeAuthenticator is only used on T+ 204 Log.e(TAG, "removeCarrierPrivilegesListener API is not available"); 205 } 206 } 207 getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex)208 private String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex) { 209 try { 210 return mTelephonyManagerShim.getCarrierServicePackageNameForLogicalSlot( 211 logicalSlotIndex); 212 } catch (UnsupportedApiLevelException unsupportedApiLevelException) { 213 // Should not happen since CarrierPrivilegeAuthenticator is only used on T+ 214 Log.e(TAG, "getCarrierServicePackageNameForLogicalSlot API is not available"); 215 } 216 return null; 217 } 218 unregisterCarrierPrivilegesListeners()219 private void unregisterCarrierPrivilegesListeners() { 220 for (CarrierPrivilegesListenerShim carrierPrivilegesListener : 221 mCarrierPrivilegesChangedListeners) { 222 removeCarrierPrivilegesListener(carrierPrivilegesListener); 223 } 224 mCarrierPrivilegesChangedListeners.clear(); 225 } 226 227 /** 228 * Check if a UID is the carrier service app of the subscription ID in the provided capabilities 229 * 230 * This returns whether the passed UID is the carrier service package for the subscription ID 231 * stored in the telephony network specifier in the passed network capabilities. 232 * If the capabilities don't code for a cellular network, or if they don't have the 233 * subscription ID in their specifier, this returns false. 234 * 235 * This method can be used to check that a network request for {@link NET_CAPABILITY_CBS} is 236 * allowed for the UID of a caller, which must hold carrier privilege and provide the carrier 237 * config. 238 * It can also be used to check that a factory is entitled to grant access to a given network 239 * to a given UID on grounds that it is the carrier service package. 240 * 241 * @param callingUid uid of the app claimed to be the carrier service package. 242 * @param networkCapabilities the network capabilities for which carrier privilege is checked. 243 * @return true if uid provides the relevant carrier config else false. 244 */ hasCarrierPrivilegeForNetworkCapabilities(int callingUid, @NonNull NetworkCapabilities networkCapabilities)245 public boolean hasCarrierPrivilegeForNetworkCapabilities(int callingUid, 246 @NonNull NetworkCapabilities networkCapabilities) { 247 if (callingUid == Process.INVALID_UID) return false; 248 if (!networkCapabilities.hasSingleTransport(TRANSPORT_CELLULAR)) return false; 249 final int subId = getSubIdFromNetworkSpecifier(networkCapabilities.getNetworkSpecifier()); 250 if (SubscriptionManager.INVALID_SUBSCRIPTION_ID == subId) return false; 251 return callingUid == getCarrierServiceUidForSubId(subId); 252 } 253 254 @VisibleForTesting updateCarrierServiceUid()255 void updateCarrierServiceUid() { 256 synchronized (mLock) { 257 mCarrierServiceUid = new int[mModemCount]; 258 for (int i = 0; i < mModemCount; i++) { 259 mCarrierServiceUid[i] = getCarrierServicePackageUidForSlot(i); 260 } 261 } 262 } 263 264 @VisibleForTesting getCarrierServiceUidForSubId(int subId)265 int getCarrierServiceUidForSubId(int subId) { 266 final int slotId = getSlotIndex(subId); 267 synchronized (mLock) { 268 if (slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX && slotId < mModemCount) { 269 return mCarrierServiceUid[slotId]; 270 } 271 } 272 return Process.INVALID_UID; 273 } 274 275 @VisibleForTesting getSlotIndex(int subId)276 protected int getSlotIndex(int subId) { 277 return SubscriptionManager.getSlotIndex(subId); 278 } 279 280 @VisibleForTesting getSubIdFromNetworkSpecifier(NetworkSpecifier specifier)281 int getSubIdFromNetworkSpecifier(NetworkSpecifier specifier) { 282 if (specifier instanceof TelephonyNetworkSpecifier) { 283 return ((TelephonyNetworkSpecifier) specifier).getSubscriptionId(); 284 } 285 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 286 } 287 288 @VisibleForTesting getUidForPackage(String pkgName)289 int getUidForPackage(String pkgName) { 290 if (pkgName == null) { 291 return Process.INVALID_UID; 292 } 293 try { 294 PackageManager pm = mContext.getPackageManager(); 295 if (pm != null) { 296 ApplicationInfo applicationInfo = pm.getApplicationInfo(pkgName, 0); 297 if (applicationInfo != null) { 298 return applicationInfo.uid; 299 } 300 } 301 } catch (PackageManager.NameNotFoundException exception) { 302 // Didn't find package. Try other users 303 Log.i(TAG, "Unable to find uid for package " + pkgName); 304 } 305 return Process.INVALID_UID; 306 } 307 308 @VisibleForTesting getCarrierServicePackageUidForSlot(int slotId)309 int getCarrierServicePackageUidForSlot(int slotId) { 310 return getUidForPackage(getCarrierServicePackageNameForLogicalSlot(slotId)); 311 } 312 } 313