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.TRANSPORT_CELLULAR; 20 import static android.net.NetworkCapabilities.TRANSPORT_WIFI; 21 22 import static com.android.net.module.util.HandlerUtils.ensureRunningOnHandlerThread; 23 import static com.android.server.connectivity.ConnectivityFlags.CARRIER_SERVICE_CHANGED_USE_CALLBACK; 24 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.content.BroadcastReceiver; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.IntentFilter; 31 import android.content.pm.ApplicationInfo; 32 import android.content.pm.PackageManager; 33 import android.net.NetworkCapabilities; 34 import android.net.NetworkSpecifier; 35 import android.net.TelephonyNetworkSpecifier; 36 import android.net.TransportInfo; 37 import android.net.wifi.WifiInfo; 38 import android.os.Handler; 39 import android.os.HandlerThread; 40 import android.os.Process; 41 import android.telephony.SubscriptionManager; 42 import android.telephony.TelephonyManager; 43 import android.util.Log; 44 import android.util.SparseArray; 45 46 import com.android.internal.annotations.GuardedBy; 47 import com.android.internal.annotations.VisibleForTesting; 48 import com.android.internal.util.IndentingPrintWriter; 49 import com.android.modules.utils.HandlerExecutor; 50 import com.android.modules.utils.build.SdkLevel; 51 import com.android.net.module.util.DeviceConfigUtils; 52 import com.android.networkstack.apishim.TelephonyManagerShimImpl; 53 import com.android.networkstack.apishim.common.TelephonyManagerShim; 54 import com.android.networkstack.apishim.common.TelephonyManagerShim.CarrierPrivilegesListenerShim; 55 import com.android.networkstack.apishim.common.UnsupportedApiLevelException; 56 57 import java.util.ArrayList; 58 import java.util.List; 59 import java.util.concurrent.Executor; 60 import java.util.function.BiConsumer; 61 62 /** 63 * Tracks the uid of the carrier privileged app that provides the carrier config. 64 * Authenticates if the caller has same uid as 65 * carrier privileged app that provides the carrier config 66 * @hide 67 */ 68 public class CarrierPrivilegeAuthenticator { 69 private static final String TAG = CarrierPrivilegeAuthenticator.class.getSimpleName(); 70 private static final boolean DBG = true; 71 72 // The context is for the current user (system server) 73 private final Context mContext; 74 private final TelephonyManagerShim mTelephonyManagerShim; 75 private final TelephonyManager mTelephonyManager; 76 @GuardedBy("mLock") 77 private final SparseArray<CarrierServiceUidWithSubId> mCarrierServiceUidWithSubId = 78 new SparseArray<>(2 /* initialCapacity */); 79 @GuardedBy("mLock") 80 private int mModemCount = 0; 81 private final Object mLock = new Object(); 82 private final Handler mHandler; 83 @NonNull 84 private final List<PrivilegeListener> mCarrierPrivilegesChangedListeners = new ArrayList<>(); 85 private final boolean mUseCallbacksForServiceChanged; 86 private final boolean mRequestRestrictedWifiEnabled; 87 @NonNull 88 private final BiConsumer<Integer, Integer> mListener; 89 CarrierPrivilegeAuthenticator(@onNull final Context c, @NonNull final Dependencies deps, @NonNull final TelephonyManager t, @NonNull final TelephonyManagerShim telephonyManagerShim, final boolean requestRestrictedWifiEnabled, @NonNull BiConsumer<Integer, Integer> listener, @NonNull final Handler connectivityServiceHandler)90 public CarrierPrivilegeAuthenticator(@NonNull final Context c, 91 @NonNull final Dependencies deps, 92 @NonNull final TelephonyManager t, 93 @NonNull final TelephonyManagerShim telephonyManagerShim, 94 final boolean requestRestrictedWifiEnabled, 95 @NonNull BiConsumer<Integer, Integer> listener, 96 @NonNull final Handler connectivityServiceHandler) { 97 mContext = c; 98 mTelephonyManager = t; 99 mTelephonyManagerShim = telephonyManagerShim; 100 mUseCallbacksForServiceChanged = deps.isFeatureEnabled( 101 c, CARRIER_SERVICE_CHANGED_USE_CALLBACK); 102 mRequestRestrictedWifiEnabled = requestRestrictedWifiEnabled; 103 mListener = listener; 104 if (mRequestRestrictedWifiEnabled) { 105 mHandler = connectivityServiceHandler; 106 } else { 107 final HandlerThread thread = deps.makeHandlerThread(); 108 thread.start(); 109 mHandler = new Handler(thread.getLooper()); 110 synchronized (mLock) { 111 registerSimConfigChangedReceiver(); 112 simConfigChanged(); 113 } 114 } 115 } 116 registerSimConfigChangedReceiver()117 private void registerSimConfigChangedReceiver() { 118 final IntentFilter filter = new IntentFilter(); 119 filter.addAction(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED); 120 // Never unregistered because the system server never stops 121 mContext.registerReceiver(new BroadcastReceiver() { 122 @Override 123 public void onReceive(final Context context, final Intent intent) { 124 switch (intent.getAction()) { 125 case TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED: 126 simConfigChanged(); 127 break; 128 default: 129 Log.d(TAG, "Unknown intent received, action: " + intent.getAction()); 130 } 131 } 132 }, filter, null, mHandler); 133 } 134 135 /** 136 * Start CarrierPrivilegeAuthenticator 137 */ start()138 public void start() { 139 if (mRequestRestrictedWifiEnabled) { 140 registerSimConfigChangedReceiver(); 141 mHandler.post(this::simConfigChanged); 142 } 143 } 144 CarrierPrivilegeAuthenticator(@onNull final Context c, @NonNull final TelephonyManager t, final boolean requestRestrictedWifiEnabled, @NonNull BiConsumer<Integer, Integer> listener, @NonNull final Handler connectivityServiceHandler)145 public CarrierPrivilegeAuthenticator(@NonNull final Context c, 146 @NonNull final TelephonyManager t, final boolean requestRestrictedWifiEnabled, 147 @NonNull BiConsumer<Integer, Integer> listener, 148 @NonNull final Handler connectivityServiceHandler) { 149 this(c, new Dependencies(), t, TelephonyManagerShimImpl.newInstance(t), 150 requestRestrictedWifiEnabled, listener, connectivityServiceHandler); 151 } 152 153 public static class Dependencies { 154 /** 155 * Create a HandlerThread to use in CarrierPrivilegeAuthenticator. 156 */ makeHandlerThread()157 public HandlerThread makeHandlerThread() { 158 return new HandlerThread(TAG); 159 } 160 161 /** 162 * @see DeviceConfigUtils#isTetheringFeatureEnabled 163 */ isFeatureEnabled(Context context, String name)164 public boolean isFeatureEnabled(Context context, String name) { 165 return DeviceConfigUtils.isTetheringFeatureEnabled(context, name); 166 } 167 } 168 simConfigChanged()169 private void simConfigChanged() { 170 // If mRequestRestrictedWifiEnabled is false, constructor calls simConfigChanged 171 if (mRequestRestrictedWifiEnabled) { 172 ensureRunningOnHandlerThread(mHandler); 173 } 174 synchronized (mLock) { 175 unregisterCarrierPrivilegesListeners(); 176 mModemCount = mTelephonyManager.getActiveModemCount(); 177 registerCarrierPrivilegesListeners(mModemCount); 178 if (!mUseCallbacksForServiceChanged) updateCarrierServiceUid(); 179 } 180 } 181 182 private static class CarrierServiceUidWithSubId { 183 final int mUid; 184 final int mSubId; 185 CarrierServiceUidWithSubId(int uid, int subId)186 CarrierServiceUidWithSubId(int uid, int subId) { 187 mUid = uid; 188 mSubId = subId; 189 } 190 191 @Override equals(Object obj)192 public boolean equals(Object obj) { 193 if (!(obj instanceof CarrierServiceUidWithSubId)) { 194 return false; 195 } 196 CarrierServiceUidWithSubId compare = (CarrierServiceUidWithSubId) obj; 197 return (mUid == compare.mUid && mSubId == compare.mSubId); 198 } 199 200 @Override hashCode()201 public int hashCode() { 202 return mUid * 31 + mSubId; 203 } 204 } 205 private class PrivilegeListener implements CarrierPrivilegesListenerShim { 206 public final int mLogicalSlot; 207 PrivilegeListener(final int logicalSlot)208 PrivilegeListener(final int logicalSlot) { 209 mLogicalSlot = logicalSlot; 210 } 211 212 @Override onCarrierPrivilegesChanged( @onNull List<String> privilegedPackageNames, @NonNull int[] privilegedUids)213 public void onCarrierPrivilegesChanged( 214 @NonNull List<String> privilegedPackageNames, 215 @NonNull int[] privilegedUids) { 216 ensureRunningOnHandlerThread(mHandler); 217 if (mUseCallbacksForServiceChanged) return; 218 // Re-trigger the synchronous check (which is also very cheap due 219 // to caching in CarrierPrivilegesTracker). This allows consistency 220 // with the onSubscriptionsChangedListener and broadcasts. 221 updateCarrierServiceUid(); 222 } 223 224 @Override onCarrierServiceChanged(@ullable final String carrierServicePackageName, final int carrierServiceUid)225 public void onCarrierServiceChanged(@Nullable final String carrierServicePackageName, 226 final int carrierServiceUid) { 227 ensureRunningOnHandlerThread(mHandler); 228 if (!mUseCallbacksForServiceChanged) { 229 // Re-trigger the synchronous check (which is also very cheap due 230 // to caching in CarrierPrivilegesTracker). This allows consistency 231 // with the onSubscriptionsChangedListener and broadcasts. 232 updateCarrierServiceUid(); 233 return; 234 } 235 synchronized (mLock) { 236 CarrierServiceUidWithSubId oldPair = 237 mCarrierServiceUidWithSubId.get(mLogicalSlot); 238 int subId = getSubId(mLogicalSlot); 239 mCarrierServiceUidWithSubId.put( 240 mLogicalSlot, 241 new CarrierServiceUidWithSubId(carrierServiceUid, subId)); 242 if (oldPair != null 243 && oldPair.mUid != Process.INVALID_UID 244 && oldPair.mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID 245 && !oldPair.equals(mCarrierServiceUidWithSubId.get(mLogicalSlot))) { 246 mListener.accept(oldPair.mUid, oldPair.mSubId); 247 } 248 } 249 } 250 } 251 registerCarrierPrivilegesListeners(final int modemCount)252 private void registerCarrierPrivilegesListeners(final int modemCount) { 253 final HandlerExecutor executor = new HandlerExecutor(mHandler); 254 try { 255 for (int i = 0; i < modemCount; i++) { 256 PrivilegeListener carrierPrivilegesListener = new PrivilegeListener(i); 257 addCarrierPrivilegesListener(executor, carrierPrivilegesListener); 258 mCarrierPrivilegesChangedListeners.add(carrierPrivilegesListener); 259 } 260 } catch (IllegalArgumentException e) { 261 Log.e(TAG, "Encountered exception registering carrier privileges listeners", e); 262 } 263 } 264 265 @GuardedBy("mLock") unregisterCarrierPrivilegesListeners()266 private void unregisterCarrierPrivilegesListeners() { 267 for (PrivilegeListener carrierPrivilegesListener : mCarrierPrivilegesChangedListeners) { 268 removeCarrierPrivilegesListener(carrierPrivilegesListener); 269 CarrierServiceUidWithSubId oldPair = 270 mCarrierServiceUidWithSubId.get(carrierPrivilegesListener.mLogicalSlot); 271 mCarrierServiceUidWithSubId.remove(carrierPrivilegesListener.mLogicalSlot); 272 if (oldPair != null 273 && oldPair.mUid != Process.INVALID_UID 274 && oldPair.mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 275 mListener.accept(oldPair.mUid, oldPair.mSubId); 276 } 277 } 278 mCarrierPrivilegesChangedListeners.clear(); 279 } 280 getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex)281 private String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex) { 282 try { 283 return mTelephonyManagerShim.getCarrierServicePackageNameForLogicalSlot( 284 logicalSlotIndex); 285 } catch (UnsupportedApiLevelException unsupportedApiLevelException) { 286 // Should not happen since CarrierPrivilegeAuthenticator is only used on T+ 287 Log.e(TAG, "getCarrierServicePackageNameForLogicalSlot API is not available"); 288 } 289 return null; 290 } 291 292 /** 293 * Check if a UID is the carrier service app of the subscription ID in the provided capabilities 294 * 295 * This returns whether the passed UID is the carrier service package for the subscription ID 296 * stored in the telephony network specifier in the passed network capabilities. 297 * If the capabilities don't code for a cellular or Wi-Fi network, or if they don't have the 298 * subscription ID in their specifier, this returns false. 299 * 300 * This method can be used to check that a network request that requires the UID to be 301 * the carrier service UID is indeed called by such a UID. An example of such a network could 302 * be a network with the {@link android.net.NetworkCapabilities#NET_CAPABILITY_CBS} 303 * capability. 304 * It can also be used to check that a factory is entitled to grant access to a given network 305 * to a given UID on grounds that it is the carrier service package. 306 * 307 * @param callingUid uid of the app claimed to be the carrier service package. 308 * @param networkCapabilities the network capabilities for which carrier privilege is checked. 309 * @return true if uid provides the relevant carrier config else false. 310 */ isCarrierServiceUidForNetworkCapabilities(int callingUid, @NonNull NetworkCapabilities networkCapabilities)311 public boolean isCarrierServiceUidForNetworkCapabilities(int callingUid, 312 @NonNull NetworkCapabilities networkCapabilities) { 313 if (callingUid == Process.INVALID_UID) { 314 return false; 315 } 316 int subId = getSubIdFromNetworkCapabilities(networkCapabilities); 317 if (SubscriptionManager.INVALID_SUBSCRIPTION_ID == subId) { 318 return false; 319 } 320 return callingUid == getCarrierServiceUidForSubId(subId); 321 } 322 323 /** 324 * Extract the SubscriptionId from the NetworkCapabilities. 325 * 326 * @param networkCapabilities the network capabilities which may contains the SubscriptionId. 327 * @return the SubscriptionId. 328 */ getSubIdFromNetworkCapabilities(@onNull NetworkCapabilities networkCapabilities)329 public int getSubIdFromNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { 330 int subId; 331 if (networkCapabilities.hasSingleTransportBesidesTest(TRANSPORT_CELLULAR)) { 332 subId = getSubIdFromTelephonySpecifier(networkCapabilities.getNetworkSpecifier()); 333 } else if (networkCapabilities.hasSingleTransportBesidesTest(TRANSPORT_WIFI)) { 334 subId = getSubIdFromWifiTransportInfo(networkCapabilities.getTransportInfo()); 335 } else { 336 subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 337 } 338 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID 339 && mRequestRestrictedWifiEnabled 340 && networkCapabilities.getSubscriptionIds().size() == 1) { 341 subId = networkCapabilities.getSubscriptionIds().toArray(new Integer[0])[0]; 342 } 343 344 if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID 345 && !networkCapabilities.getSubscriptionIds().contains(subId)) { 346 // Ideally, the code above should just use networkCapabilities.getSubscriptionIds() 347 // for simplicity and future-proofing. However, this is not the historical behavior, 348 // and there is no enforcement that they do not differ, so log a terrible failure if 349 // they do not match to gain confidence this never happens. 350 // TODO : when there is confidence that this never happens, rewrite the code above 351 // with NetworkCapabilities#getSubscriptionIds. 352 Log.wtf(TAG, "NetworkCapabilities subIds are inconsistent between " 353 + "specifier/transportInfo and mSubIds : " + networkCapabilities); 354 } 355 return subId; 356 } 357 358 @VisibleForTesting getSubId(int slotIndex)359 protected int getSubId(int slotIndex) { 360 if (SdkLevel.isAtLeastU()) { 361 return SubscriptionManager.getSubscriptionId(slotIndex); 362 } else { 363 SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class); 364 int[] subIds = sm.getSubscriptionIds(slotIndex); 365 if (subIds != null && subIds.length > 0) { 366 return subIds[0]; 367 } 368 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 369 } 370 } 371 372 @VisibleForTesting updateCarrierServiceUid()373 void updateCarrierServiceUid() { 374 synchronized (mLock) { 375 SparseArray<CarrierServiceUidWithSubId> copy = mCarrierServiceUidWithSubId.clone(); 376 mCarrierServiceUidWithSubId.clear(); 377 for (int i = 0; i < mModemCount; i++) { 378 int subId = getSubId(i); 379 mCarrierServiceUidWithSubId.put( 380 i, 381 new CarrierServiceUidWithSubId( 382 getCarrierServicePackageUidForSlot(i), subId)); 383 } 384 for (int i = 0; i < copy.size(); ++i) { 385 CarrierServiceUidWithSubId oldPair = copy.valueAt(i); 386 CarrierServiceUidWithSubId newPair = mCarrierServiceUidWithSubId.get(copy.keyAt(i)); 387 if (oldPair.mUid != Process.INVALID_UID 388 && oldPair.mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID 389 && !oldPair.equals(newPair)) { 390 mListener.accept(oldPair.mUid, oldPair.mSubId); 391 } 392 } 393 } 394 } 395 396 @VisibleForTesting getCarrierServiceUidForSubId(int subId)397 int getCarrierServiceUidForSubId(int subId) { 398 synchronized (mLock) { 399 for (int i = 0; i < mCarrierServiceUidWithSubId.size(); ++i) { 400 if (mCarrierServiceUidWithSubId.valueAt(i).mSubId == subId) { 401 return mCarrierServiceUidWithSubId.valueAt(i).mUid; 402 } 403 } 404 return Process.INVALID_UID; 405 } 406 } 407 408 @VisibleForTesting getUidForPackage(String pkgName)409 int getUidForPackage(String pkgName) { 410 if (pkgName == null) { 411 return Process.INVALID_UID; 412 } 413 try { 414 PackageManager pm = mContext.getPackageManager(); 415 if (pm != null) { 416 ApplicationInfo applicationInfo = pm.getApplicationInfo(pkgName, 0); 417 if (applicationInfo != null) { 418 return applicationInfo.uid; 419 } 420 } 421 } catch (PackageManager.NameNotFoundException exception) { 422 // Didn't find package. Try other users 423 Log.i(TAG, "Unable to find uid for package " + pkgName); 424 } 425 return Process.INVALID_UID; 426 } 427 428 @VisibleForTesting getCarrierServicePackageUidForSlot(int slotId)429 int getCarrierServicePackageUidForSlot(int slotId) { 430 return getUidForPackage(getCarrierServicePackageNameForLogicalSlot(slotId)); 431 } 432 433 @VisibleForTesting getSubIdFromTelephonySpecifier(@ullable final NetworkSpecifier specifier)434 int getSubIdFromTelephonySpecifier(@Nullable final NetworkSpecifier specifier) { 435 if (specifier instanceof TelephonyNetworkSpecifier) { 436 return ((TelephonyNetworkSpecifier) specifier).getSubscriptionId(); 437 } 438 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 439 } 440 getSubIdFromWifiTransportInfo(@ullable final TransportInfo info)441 int getSubIdFromWifiTransportInfo(@Nullable final TransportInfo info) { 442 if (info instanceof WifiInfo) { 443 return ((WifiInfo) info).getSubscriptionId(); 444 } 445 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 446 } 447 448 // Helper methods to avoid having to deal with UnsupportedApiLevelException. addCarrierPrivilegesListener(@onNull final Executor executor, @NonNull final PrivilegeListener listener)449 private void addCarrierPrivilegesListener(@NonNull final Executor executor, 450 @NonNull final PrivilegeListener listener) { 451 try { 452 mTelephonyManagerShim.addCarrierPrivilegesListener(listener.mLogicalSlot, executor, 453 listener); 454 } catch (UnsupportedApiLevelException unsupportedApiLevelException) { 455 // Should not happen since CarrierPrivilegeAuthenticator is only used on T+ 456 Log.e(TAG, "addCarrierPrivilegesListener API is not available"); 457 } 458 } 459 removeCarrierPrivilegesListener(PrivilegeListener listener)460 private void removeCarrierPrivilegesListener(PrivilegeListener listener) { 461 try { 462 mTelephonyManagerShim.removeCarrierPrivilegesListener(listener); 463 } catch (UnsupportedApiLevelException unsupportedApiLevelException) { 464 // Should not happen since CarrierPrivilegeAuthenticator is only used on T+ 465 Log.e(TAG, "removeCarrierPrivilegesListener API is not available"); 466 } 467 } 468 dump(IndentingPrintWriter pw)469 public void dump(IndentingPrintWriter pw) { 470 pw.println("CarrierPrivilegeAuthenticator:"); 471 pw.println("mRequestRestrictedWifiEnabled = " + mRequestRestrictedWifiEnabled); 472 synchronized (mLock) { 473 for (int i = 0; i < mCarrierServiceUidWithSubId.size(); ++i) { 474 final int logicalSlot = mCarrierServiceUidWithSubId.keyAt(i); 475 final int serviceUid = mCarrierServiceUidWithSubId.valueAt(i).mUid; 476 final int subId = mCarrierServiceUidWithSubId.valueAt(i).mSubId; 477 pw.println("Logical slot = " + logicalSlot + " : uid = " + serviceUid 478 + " : subId = " + subId); 479 } 480 } 481 } 482 } 483