• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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