• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.Manifest.permission.CHANGE_NETWORK_STATE;
20 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
21 import static android.Manifest.permission.INTERNET;
22 import static android.Manifest.permission.NETWORK_STACK;
23 import static android.Manifest.permission.UPDATE_DEVICE_STATS;
24 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
25 import static android.content.pm.PackageManager.GET_PERMISSIONS;
26 import static android.content.pm.PackageManager.MATCH_ANY_USER;
27 import static android.net.ConnectivitySettingsManager.UIDS_ALLOWED_ON_RESTRICTED_NETWORKS;
28 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
29 import static android.os.Process.INVALID_UID;
30 import static android.os.Process.SYSTEM_UID;
31 
32 import static com.android.net.module.util.CollectionUtils.toIntArray;
33 
34 import android.annotation.NonNull;
35 import android.content.BroadcastReceiver;
36 import android.content.Context;
37 import android.content.Intent;
38 import android.content.IntentFilter;
39 import android.content.pm.ApplicationInfo;
40 import android.content.pm.PackageInfo;
41 import android.content.pm.PackageManager;
42 import android.content.pm.PackageManager.NameNotFoundException;
43 import android.database.ContentObserver;
44 import android.net.ConnectivitySettingsManager;
45 import android.net.INetd;
46 import android.net.UidRange;
47 import android.net.Uri;
48 import android.os.Build;
49 import android.os.RemoteException;
50 import android.os.ServiceSpecificException;
51 import android.os.SystemConfigManager;
52 import android.os.UserHandle;
53 import android.os.UserManager;
54 import android.provider.Settings;
55 import android.system.OsConstants;
56 import android.util.ArraySet;
57 import android.util.Log;
58 import android.util.SparseArray;
59 import android.util.SparseIntArray;
60 
61 import com.android.internal.annotations.GuardedBy;
62 import com.android.internal.annotations.VisibleForTesting;
63 import com.android.internal.util.IndentingPrintWriter;
64 import com.android.net.module.util.CollectionUtils;
65 
66 import java.util.ArrayList;
67 import java.util.HashMap;
68 import java.util.HashSet;
69 import java.util.List;
70 import java.util.Map;
71 import java.util.Map.Entry;
72 import java.util.Set;
73 
74 /**
75  * A utility class to inform Netd of UID permisisons.
76  * Does a mass update at boot and then monitors for app install/remove.
77  *
78  * @hide
79  */
80 public class PermissionMonitor {
81     private static final String TAG = "PermissionMonitor";
82     private static final boolean DBG = true;
83     protected static final Boolean SYSTEM = Boolean.TRUE;
84     protected static final Boolean NETWORK = Boolean.FALSE;
85     private static final int VERSION_Q = Build.VERSION_CODES.Q;
86 
87     private final PackageManager mPackageManager;
88     private final UserManager mUserManager;
89     private final SystemConfigManager mSystemConfigManager;
90     private final INetd mNetd;
91     private final Dependencies mDeps;
92     private final Context mContext;
93 
94     @GuardedBy("this")
95     private final Set<UserHandle> mUsers = new HashSet<>();
96 
97     // Keys are app uids. Values are true for SYSTEM permission and false for NETWORK permission.
98     @GuardedBy("this")
99     private final Map<Integer, Boolean> mApps = new HashMap<>();
100 
101     // Keys are active non-bypassable and fully-routed VPN's interface name, Values are uid ranges
102     // for apps under the VPN
103     @GuardedBy("this")
104     private final Map<String, Set<UidRange>> mVpnUidRanges = new HashMap<>();
105 
106     // A set of appIds for apps across all users on the device. We track appIds instead of uids
107     // directly to reduce its size and also eliminate the need to update this set when user is
108     // added/removed.
109     @GuardedBy("this")
110     private final Set<Integer> mAllApps = new HashSet<>();
111 
112     // A set of uids which are allowed to use restricted networks. The packages of these uids can't
113     // hold the CONNECTIVITY_USE_RESTRICTED_NETWORKS permission because they can't be
114     // signature|privileged apps. However, these apps should still be able to use restricted
115     // networks under certain conditions (e.g. government app using emergency services). So grant
116     // netd system permission to these uids which is listed in UIDS_ALLOWED_ON_RESTRICTED_NETWORKS.
117     @GuardedBy("this")
118     private final Set<Integer> mUidsAllowedOnRestrictedNetworks = new ArraySet<>();
119 
120     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
121         @Override
122         public void onReceive(Context context, Intent intent) {
123             final String action = intent.getAction();
124 
125             if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
126                 final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
127                 final Uri packageData = intent.getData();
128                 final String packageName =
129                         packageData != null ? packageData.getSchemeSpecificPart() : null;
130                 onPackageAdded(packageName, uid);
131             } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
132                 final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
133                 final Uri packageData = intent.getData();
134                 final String packageName =
135                         packageData != null ? packageData.getSchemeSpecificPart() : null;
136                 onPackageRemoved(packageName, uid);
137             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
138                 final String[] pkgList =
139                         intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
140                 onExternalApplicationsAvailable(pkgList);
141             } else {
142                 Log.wtf(TAG, "received unexpected intent: " + action);
143             }
144         }
145     };
146 
147     /**
148      * Dependencies of PermissionMonitor, for injection in tests.
149      */
150     @VisibleForTesting
151     public static class Dependencies {
152         /**
153          * Get device first sdk version.
154          */
getDeviceFirstSdkInt()155         public int getDeviceFirstSdkInt() {
156             return Build.VERSION.DEVICE_INITIAL_SDK_INT;
157         }
158 
159         /**
160          * Get uids allowed to use restricted networks via ConnectivitySettingsManager.
161          */
getUidsAllowedOnRestrictedNetworks(@onNull Context context)162         public Set<Integer> getUidsAllowedOnRestrictedNetworks(@NonNull Context context) {
163             return ConnectivitySettingsManager.getUidsAllowedOnRestrictedNetworks(context);
164         }
165 
166         /**
167          * Register ContentObserver for given Uri.
168          */
registerContentObserver(@onNull Context context, @NonNull Uri uri, boolean notifyForDescendants, @NonNull ContentObserver observer)169         public void registerContentObserver(@NonNull Context context, @NonNull Uri uri,
170                 boolean notifyForDescendants, @NonNull ContentObserver observer) {
171             context.getContentResolver().registerContentObserver(
172                     uri, notifyForDescendants, observer);
173         }
174     }
175 
PermissionMonitor(@onNull final Context context, @NonNull final INetd netd)176     public PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd) {
177         this(context, netd, new Dependencies());
178     }
179 
180     @VisibleForTesting
PermissionMonitor(@onNull final Context context, @NonNull final INetd netd, @NonNull final Dependencies deps)181     PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd,
182             @NonNull final Dependencies deps) {
183         mPackageManager = context.getPackageManager();
184         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
185         mSystemConfigManager = context.getSystemService(SystemConfigManager.class);
186         mNetd = netd;
187         mDeps = deps;
188         mContext = context;
189     }
190 
191     // Intended to be called only once at startup, after the system is ready. Installs a broadcast
192     // receiver to monitor ongoing UID changes, so this shouldn't/needn't be called again.
startMonitoring()193     public synchronized void startMonitoring() {
194         log("Monitoring");
195 
196         final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
197         final IntentFilter intentFilter = new IntentFilter();
198         intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
199         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
200         intentFilter.addDataScheme("package");
201         userAllContext.registerReceiver(
202                 mIntentReceiver, intentFilter, null /* broadcastPermission */,
203                 null /* scheduler */);
204 
205         final IntentFilter externalIntentFilter =
206                 new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
207         userAllContext.registerReceiver(
208                 mIntentReceiver, externalIntentFilter, null /* broadcastPermission */,
209                 null /* scheduler */);
210 
211         // Register UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting observer
212         mDeps.registerContentObserver(
213                 userAllContext,
214                 Settings.Global.getUriFor(UIDS_ALLOWED_ON_RESTRICTED_NETWORKS),
215                 false /* notifyForDescendants */,
216                 new ContentObserver(null) {
217                     @Override
218                     public void onChange(boolean selfChange) {
219                         onSettingChanged();
220                     }
221                 });
222 
223         // Read UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting and update
224         // mUidsAllowedOnRestrictedNetworks.
225         updateUidsAllowedOnRestrictedNetworks(mDeps.getUidsAllowedOnRestrictedNetworks(mContext));
226 
227         List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
228                 | MATCH_ANY_USER);
229         if (apps == null) {
230             loge("No apps");
231             return;
232         }
233 
234         SparseIntArray netdPermsUids = new SparseIntArray();
235 
236         for (PackageInfo app : apps) {
237             int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
238             if (uid < 0) {
239                 continue;
240             }
241             mAllApps.add(UserHandle.getAppId(uid));
242 
243             boolean isNetwork = hasNetworkPermission(app);
244             boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
245 
246             if (isNetwork || hasRestrictedPermission) {
247                 Boolean permission = mApps.get(UserHandle.getAppId(uid));
248                 // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
249                 // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
250                 if (permission == null || permission == NETWORK) {
251                     mApps.put(UserHandle.getAppId(uid), hasRestrictedPermission);
252                 }
253             }
254 
255             //TODO: unify the management of the permissions into one codepath.
256             int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions,
257                     app.requestedPermissionsFlags);
258             netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
259         }
260 
261         mUsers.addAll(mUserManager.getUserHandles(true /* excludeDying */));
262 
263         final SparseArray<String> netdPermToSystemPerm = new SparseArray<>();
264         netdPermToSystemPerm.put(INetd.PERMISSION_INTERNET, INTERNET);
265         netdPermToSystemPerm.put(INetd.PERMISSION_UPDATE_DEVICE_STATS, UPDATE_DEVICE_STATS);
266         for (int i = 0; i < netdPermToSystemPerm.size(); i++) {
267             final int netdPermission = netdPermToSystemPerm.keyAt(i);
268             final String systemPermission = netdPermToSystemPerm.valueAt(i);
269             final int[] hasPermissionUids =
270                     mSystemConfigManager.getSystemPermissionUids(systemPermission);
271             for (int j = 0; j < hasPermissionUids.length; j++) {
272                 final int uid = hasPermissionUids[j];
273                 netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
274             }
275         }
276         log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
277         update(mUsers, mApps, true);
278         sendPackagePermissionsToNetd(netdPermsUids);
279     }
280 
281     @VisibleForTesting
updateUidsAllowedOnRestrictedNetworks(final Set<Integer> uids)282     synchronized void updateUidsAllowedOnRestrictedNetworks(final Set<Integer> uids) {
283         mUidsAllowedOnRestrictedNetworks.clear();
284         // This is necessary for the app id to match in isUidAllowedOnRestrictedNetworks, and will
285         // grant the permission to all uids associated with the app ID. This is safe even if the app
286         // is only installed on some users because the uid cannot match some other app – this uid is
287         // in effect not installed and can't be run.
288         // TODO (b/192431153): Change appIds back to uids.
289         for (int uid : uids) {
290             mUidsAllowedOnRestrictedNetworks.add(UserHandle.getAppId(uid));
291         }
292     }
293 
294     @VisibleForTesting
isVendorApp(@onNull ApplicationInfo appInfo)295     static boolean isVendorApp(@NonNull ApplicationInfo appInfo) {
296         return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct();
297     }
298 
299     @VisibleForTesting
isCarryoverPackage(final ApplicationInfo appInfo)300     boolean isCarryoverPackage(final ApplicationInfo appInfo) {
301         if (appInfo == null) return false;
302         return (appInfo.targetSdkVersion < VERSION_Q && isVendorApp(appInfo))
303                 // Backward compatibility for b/114245686, on devices that launched before Q daemons
304                 // and apps running as the system UID are exempted from this check.
305                 || (appInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q);
306     }
307 
308     @VisibleForTesting
isUidAllowedOnRestrictedNetworks(final ApplicationInfo appInfo)309     synchronized boolean isUidAllowedOnRestrictedNetworks(final ApplicationInfo appInfo) {
310         if (appInfo == null) return false;
311         // Check whether package's uid is in allowed on restricted networks uid list. If so, this
312         // uid can have netd system permission.
313         return mUidsAllowedOnRestrictedNetworks.contains(UserHandle.getAppId(appInfo.uid));
314     }
315 
316     @VisibleForTesting
hasPermission(@onNull final PackageInfo app, @NonNull final String permission)317     boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) {
318         if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
319             return false;
320         }
321         final int index = CollectionUtils.indexOf(app.requestedPermissions, permission);
322         if (index < 0 || index >= app.requestedPermissionsFlags.length) return false;
323         return (app.requestedPermissionsFlags[index] & REQUESTED_PERMISSION_GRANTED) != 0;
324     }
325 
326     @VisibleForTesting
hasNetworkPermission(@onNull final PackageInfo app)327     boolean hasNetworkPermission(@NonNull final PackageInfo app) {
328         return hasPermission(app, CHANGE_NETWORK_STATE);
329     }
330 
331     @VisibleForTesting
hasRestrictedNetworkPermission(@onNull final PackageInfo app)332     boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) {
333         // TODO : remove carryover package check in the future(b/31479477). All apps should just
334         //  request the appropriate permission for their use case since android Q.
335         return isCarryoverPackage(app.applicationInfo)
336                 || isUidAllowedOnRestrictedNetworks(app.applicationInfo)
337                 || hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK)
338                 || hasPermission(app, NETWORK_STACK)
339                 || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
340     }
341 
342     /** Returns whether the given uid has using background network permission. */
hasUseBackgroundNetworksPermission(final int uid)343     public synchronized boolean hasUseBackgroundNetworksPermission(final int uid) {
344         // Apps with any of the CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_INTERNAL or
345         // CONNECTIVITY_USE_RESTRICTED_NETWORKS permission has the permission to use background
346         // networks. mApps contains the result of checks for both hasNetworkPermission and
347         // hasRestrictedNetworkPermission. If uid is in the mApps list that means uid has one of
348         // permissions at least.
349         return mApps.containsKey(UserHandle.getAppId(uid));
350     }
351 
352     /**
353      * Returns whether the given uid has permission to use restricted networks.
354      */
hasRestrictedNetworksPermission(int uid)355     public synchronized boolean hasRestrictedNetworksPermission(int uid) {
356         return Boolean.TRUE.equals(mApps.get(UserHandle.getAppId(uid)));
357     }
358 
update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add)359     private void update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add) {
360         List<Integer> network = new ArrayList<>();
361         List<Integer> system = new ArrayList<>();
362         for (Entry<Integer, Boolean> app : apps.entrySet()) {
363             List<Integer> list = app.getValue() ? system : network;
364             for (UserHandle user : users) {
365                 if (user == null) continue;
366 
367                 list.add(user.getUid(app.getKey()));
368             }
369         }
370         try {
371             if (add) {
372                 mNetd.networkSetPermissionForUser(INetd.PERMISSION_NETWORK, toIntArray(network));
373                 mNetd.networkSetPermissionForUser(INetd.PERMISSION_SYSTEM, toIntArray(system));
374             } else {
375                 mNetd.networkClearPermissionForUser(toIntArray(network));
376                 mNetd.networkClearPermissionForUser(toIntArray(system));
377             }
378         } catch (RemoteException e) {
379             loge("Exception when updating permissions: " + e);
380         }
381     }
382 
383     /**
384      * Called when a user is added. See {link #ACTION_USER_ADDED}.
385      *
386      * @param user The integer userHandle of the added user. See {@link #EXTRA_USER_HANDLE}.
387      *
388      * @hide
389      */
onUserAdded(@onNull UserHandle user)390     public synchronized void onUserAdded(@NonNull UserHandle user) {
391         mUsers.add(user);
392 
393         Set<UserHandle> users = new HashSet<>();
394         users.add(user);
395         update(users, mApps, true);
396     }
397 
398     /**
399      * Called when an user is removed. See {link #ACTION_USER_REMOVED}.
400      *
401      * @param user The integer userHandle of the removed user. See {@link #EXTRA_USER_HANDLE}.
402      *
403      * @hide
404      */
onUserRemoved(@onNull UserHandle user)405     public synchronized void onUserRemoved(@NonNull UserHandle user) {
406         mUsers.remove(user);
407 
408         Set<UserHandle> users = new HashSet<>();
409         users.add(user);
410         update(users, mApps, false);
411     }
412 
413     /**
414      * Compare the current network permission and the given package's permission to find out highest
415      * permission for the uid.
416      *
417      * @param currentPermission Current uid network permission
418      * @param name The package has same uid that need compare its permission to update uid network
419      *             permission.
420      */
421     @VisibleForTesting
highestPermissionForUid(Boolean currentPermission, String name)422     protected Boolean highestPermissionForUid(Boolean currentPermission, String name) {
423         if (currentPermission == SYSTEM) {
424             return currentPermission;
425         }
426         try {
427             final PackageInfo app = mPackageManager.getPackageInfo(name,
428                     GET_PERMISSIONS | MATCH_ANY_USER);
429             final boolean isNetwork = hasNetworkPermission(app);
430             final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
431             if (isNetwork || hasRestrictedPermission) {
432                 currentPermission = hasRestrictedPermission;
433             }
434         } catch (NameNotFoundException e) {
435             // App not found.
436             loge("NameNotFoundException " + name);
437         }
438         return currentPermission;
439     }
440 
getPermissionForUid(final int uid)441     private int getPermissionForUid(final int uid) {
442         int permission = INetd.PERMISSION_NONE;
443         // Check all the packages for this UID. The UID has the permission if any of the
444         // packages in it has the permission.
445         final String[] packages = mPackageManager.getPackagesForUid(uid);
446         if (packages != null && packages.length > 0) {
447             for (String name : packages) {
448                 final PackageInfo app = getPackageInfo(name);
449                 if (app != null && app.requestedPermissions != null) {
450                     permission |= getNetdPermissionMask(app.requestedPermissions,
451                             app.requestedPermissionsFlags);
452                 }
453             }
454         } else {
455             // The last package of this uid is removed from device. Clean the package up.
456             permission = INetd.PERMISSION_UNINSTALLED;
457         }
458         return permission;
459     }
460 
461     /**
462      * Called when a package is added.
463      *
464      * @param packageName The name of the new package.
465      * @param uid The uid of the new package.
466      *
467      * @hide
468      */
onPackageAdded(@onNull final String packageName, final int uid)469     public synchronized void onPackageAdded(@NonNull final String packageName, final int uid) {
470         // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
471         //  using appId instead of uid actually
472         sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));
473 
474         // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
475         // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
476         final int appId = UserHandle.getAppId(uid);
477         final Boolean permission = highestPermissionForUid(mApps.get(appId), packageName);
478         if (permission != mApps.get(appId)) {
479             mApps.put(appId, permission);
480 
481             Map<Integer, Boolean> apps = new HashMap<>();
482             apps.put(appId, permission);
483             update(mUsers, apps, true);
484         }
485 
486         // If the newly-installed package falls within some VPN's uid range, update Netd with it.
487         // This needs to happen after the mApps update above, since removeBypassingUids() depends
488         // on mApps to check if the package can bypass VPN.
489         for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
490             if (UidRange.containsUid(vpn.getValue(), uid)) {
491                 final Set<Integer> changedUids = new HashSet<>();
492                 changedUids.add(uid);
493                 removeBypassingUids(changedUids, /* vpnAppUid */ -1);
494                 updateVpnUids(vpn.getKey(), changedUids, true);
495             }
496         }
497         mAllApps.add(appId);
498     }
499 
highestUidNetworkPermission(int uid)500     private Boolean highestUidNetworkPermission(int uid) {
501         Boolean permission = null;
502         final String[] packages = mPackageManager.getPackagesForUid(uid);
503         if (!CollectionUtils.isEmpty(packages)) {
504             for (String name : packages) {
505                 // If multiple packages have the same UID, give the UID all permissions that
506                 // any package in that UID has.
507                 permission = highestPermissionForUid(permission, name);
508                 if (permission == SYSTEM) {
509                     break;
510                 }
511             }
512         }
513         return permission;
514     }
515 
516     /**
517      * Called when a package is removed.
518      *
519      * @param packageName The name of the removed package or null.
520      * @param uid containing the integer uid previously assigned to the package.
521      *
522      * @hide
523      */
onPackageRemoved(@onNull final String packageName, final int uid)524     public synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) {
525         // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
526         //  using appId instead of uid actually
527         sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));
528 
529         // If the newly-removed package falls within some VPN's uid range, update Netd with it.
530         // This needs to happen before the mApps update below, since removeBypassingUids() depends
531         // on mApps to check if the package can bypass VPN.
532         for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
533             if (UidRange.containsUid(vpn.getValue(), uid)) {
534                 final Set<Integer> changedUids = new HashSet<>();
535                 changedUids.add(uid);
536                 removeBypassingUids(changedUids, /* vpnAppUid */ -1);
537                 updateVpnUids(vpn.getKey(), changedUids, false);
538             }
539         }
540         // If the package has been removed from all users on the device, clear it form mAllApps.
541         if (mPackageManager.getNameForUid(uid) == null) {
542             mAllApps.remove(UserHandle.getAppId(uid));
543         }
544 
545         Map<Integer, Boolean> apps = new HashMap<>();
546         final Boolean permission = highestUidNetworkPermission(uid);
547         if (permission == SYSTEM) {
548             // An app with this UID still has the SYSTEM permission.
549             // Therefore, this UID must already have the SYSTEM permission.
550             // Nothing to do.
551             return;
552         }
553 
554         final int appId = UserHandle.getAppId(uid);
555         if (permission == mApps.get(appId)) {
556             // The permissions of this UID have not changed. Nothing to do.
557             return;
558         } else if (permission != null) {
559             mApps.put(appId, permission);
560             apps.put(appId, permission);
561             update(mUsers, apps, true);
562         } else {
563             mApps.remove(appId);
564             apps.put(appId, NETWORK);  // doesn't matter which permission we pick here
565             update(mUsers, apps, false);
566         }
567     }
568 
getNetdPermissionMask(String[] requestedPermissions, int[] requestedPermissionsFlags)569     private static int getNetdPermissionMask(String[] requestedPermissions,
570                                              int[] requestedPermissionsFlags) {
571         int permissions = 0;
572         if (requestedPermissions == null || requestedPermissionsFlags == null) return permissions;
573         for (int i = 0; i < requestedPermissions.length; i++) {
574             if (requestedPermissions[i].equals(INTERNET)
575                     && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
576                 permissions |= INetd.PERMISSION_INTERNET;
577             }
578             if (requestedPermissions[i].equals(UPDATE_DEVICE_STATS)
579                     && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
580                 permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS;
581             }
582         }
583         return permissions;
584     }
585 
getPackageInfo(String packageName)586     private PackageInfo getPackageInfo(String packageName) {
587         try {
588             PackageInfo app = mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS
589                     | MATCH_ANY_USER);
590             return app;
591         } catch (NameNotFoundException e) {
592             return null;
593         }
594     }
595 
596     /**
597      * Called when a new set of UID ranges are added to an active VPN network
598      *
599      * @param iface The active VPN network's interface name
600      * @param rangesToAdd The new UID ranges to be added to the network
601      * @param vpnAppUid The uid of the VPN app
602      */
onVpnUidRangesAdded(@onNull String iface, Set<UidRange> rangesToAdd, int vpnAppUid)603     public synchronized void onVpnUidRangesAdded(@NonNull String iface, Set<UidRange> rangesToAdd,
604             int vpnAppUid) {
605         // Calculate the list of new app uids under the VPN due to the new UID ranges and update
606         // Netd about them. Because mAllApps only contains appIds instead of uids, the result might
607         // be an overestimation if an app is not installed on the user on which the VPN is running,
608         // but that's safe.
609         final Set<Integer> changedUids = intersectUids(rangesToAdd, mAllApps);
610         removeBypassingUids(changedUids, vpnAppUid);
611         updateVpnUids(iface, changedUids, true);
612         if (mVpnUidRanges.containsKey(iface)) {
613             mVpnUidRanges.get(iface).addAll(rangesToAdd);
614         } else {
615             mVpnUidRanges.put(iface, new HashSet<UidRange>(rangesToAdd));
616         }
617     }
618 
619     /**
620      * Called when a set of UID ranges are removed from an active VPN network
621      *
622      * @param iface The VPN network's interface name
623      * @param rangesToRemove Existing UID ranges to be removed from the VPN network
624      * @param vpnAppUid The uid of the VPN app
625      */
onVpnUidRangesRemoved(@onNull String iface, Set<UidRange> rangesToRemove, int vpnAppUid)626     public synchronized void onVpnUidRangesRemoved(@NonNull String iface,
627             Set<UidRange> rangesToRemove, int vpnAppUid) {
628         // Calculate the list of app uids that are no longer under the VPN due to the removed UID
629         // ranges and update Netd about them.
630         final Set<Integer> changedUids = intersectUids(rangesToRemove, mAllApps);
631         removeBypassingUids(changedUids, vpnAppUid);
632         updateVpnUids(iface, changedUids, false);
633         Set<UidRange> existingRanges = mVpnUidRanges.getOrDefault(iface, null);
634         if (existingRanges == null) {
635             loge("Attempt to remove unknown vpn uid Range iface = " + iface);
636             return;
637         }
638         existingRanges.removeAll(rangesToRemove);
639         if (existingRanges.size() == 0) {
640             mVpnUidRanges.remove(iface);
641         }
642     }
643 
644     /**
645      * Compute the intersection of a set of UidRanges and appIds. Returns a set of uids
646      * that satisfies:
647      *   1. falls into one of the UidRange
648      *   2. matches one of the appIds
649      */
intersectUids(Set<UidRange> ranges, Set<Integer> appIds)650     private Set<Integer> intersectUids(Set<UidRange> ranges, Set<Integer> appIds) {
651         Set<Integer> result = new HashSet<>();
652         for (UidRange range : ranges) {
653             for (int userId = range.getStartUser(); userId <= range.getEndUser(); userId++) {
654                 for (int appId : appIds) {
655                     final UserHandle handle = UserHandle.of(userId);
656                     if (handle == null) continue;
657 
658                     final int uid = handle.getUid(appId);
659                     if (range.contains(uid)) {
660                         result.add(uid);
661                     }
662                 }
663             }
664         }
665         return result;
666     }
667 
668     /**
669      * Remove all apps which can elect to bypass the VPN from the list of uids
670      *
671      * An app can elect to bypass the VPN if it hold SYSTEM permission, or if its the active VPN
672      * app itself.
673      *
674      * @param uids The list of uids to operate on
675      * @param vpnAppUid The uid of the VPN app
676      */
removeBypassingUids(Set<Integer> uids, int vpnAppUid)677     private void removeBypassingUids(Set<Integer> uids, int vpnAppUid) {
678         uids.remove(vpnAppUid);
679         uids.removeIf(uid -> mApps.getOrDefault(UserHandle.getAppId(uid), NETWORK) == SYSTEM);
680     }
681 
682     /**
683      * Update netd about the list of uids that are under an active VPN connection which they cannot
684      * bypass.
685      *
686      * This is to instruct netd to set up appropriate filtering rules for these uids, such that they
687      * can only receive ingress packets from the VPN's tunnel interface (and loopback).
688      *
689      * @param iface the interface name of the active VPN connection
690      * @param add {@code true} if the uids are to be added to the interface, {@code false} if they
691      *        are to be removed from the interface.
692      */
updateVpnUids(String iface, Set<Integer> uids, boolean add)693     private void updateVpnUids(String iface, Set<Integer> uids, boolean add) {
694         if (uids.size() == 0) {
695             return;
696         }
697         try {
698             if (add) {
699                 mNetd.firewallAddUidInterfaceRules(iface, toIntArray(uids));
700             } else {
701                 mNetd.firewallRemoveUidInterfaceRules(toIntArray(uids));
702             }
703         } catch (ServiceSpecificException e) {
704             // Silently ignore exception when device does not support eBPF, otherwise just log
705             // the exception and do not crash
706             if (e.errorCode != OsConstants.EOPNOTSUPP) {
707                 loge("Exception when updating permissions: ", e);
708             }
709         } catch (RemoteException e) {
710             loge("Exception when updating permissions: ", e);
711         }
712     }
713 
714     /**
715      * Called by PackageListObserver when a package is installed/uninstalled. Send the updated
716      * permission information to netd.
717      *
718      * @param uid the app uid of the package installed
719      * @param permissions the permissions the app requested and netd cares about.
720      *
721      * @hide
722      */
723     @VisibleForTesting
sendPackagePermissionsForUid(int uid, int permissions)724     void sendPackagePermissionsForUid(int uid, int permissions) {
725         SparseIntArray netdPermissionsAppIds = new SparseIntArray();
726         netdPermissionsAppIds.put(uid, permissions);
727         sendPackagePermissionsToNetd(netdPermissionsAppIds);
728     }
729 
730     /**
731      * Called by packageManagerService to send IPC to netd. Grant or revoke the INTERNET
732      * and/or UPDATE_DEVICE_STATS permission of the uids in array.
733      *
734      * @param netdPermissionsAppIds integer pairs of uids and the permission granted to it. If the
735      * permission is 0, revoke all permissions of that uid.
736      *
737      * @hide
738      */
739     @VisibleForTesting
sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds)740     void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
741         if (mNetd == null) {
742             Log.e(TAG, "Failed to get the netd service");
743             return;
744         }
745         ArrayList<Integer> allPermissionAppIds = new ArrayList<>();
746         ArrayList<Integer> internetPermissionAppIds = new ArrayList<>();
747         ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
748         ArrayList<Integer> noPermissionAppIds = new ArrayList<>();
749         ArrayList<Integer> uninstalledAppIds = new ArrayList<>();
750         for (int i = 0; i < netdPermissionsAppIds.size(); i++) {
751             int permissions = netdPermissionsAppIds.valueAt(i);
752             switch(permissions) {
753                 case (INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS):
754                     allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
755                     break;
756                 case INetd.PERMISSION_INTERNET:
757                     internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
758                     break;
759                 case INetd.PERMISSION_UPDATE_DEVICE_STATS:
760                     updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
761                     break;
762                 case INetd.PERMISSION_NONE:
763                     noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
764                     break;
765                 case INetd.PERMISSION_UNINSTALLED:
766                     uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
767                     break;
768                 default:
769                     Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
770                             + netdPermissionsAppIds.keyAt(i));
771             }
772         }
773         try {
774             // TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids()
775             if (allPermissionAppIds.size() != 0) {
776                 mNetd.trafficSetNetPermForUids(
777                         INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
778                         toIntArray(allPermissionAppIds));
779             }
780             if (internetPermissionAppIds.size() != 0) {
781                 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
782                         toIntArray(internetPermissionAppIds));
783             }
784             if (updateStatsPermissionAppIds.size() != 0) {
785                 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
786                         toIntArray(updateStatsPermissionAppIds));
787             }
788             if (noPermissionAppIds.size() != 0) {
789                 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE,
790                         toIntArray(noPermissionAppIds));
791             }
792             if (uninstalledAppIds.size() != 0) {
793                 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UNINSTALLED,
794                         toIntArray(uninstalledAppIds));
795             }
796         } catch (RemoteException e) {
797             Log.e(TAG, "Pass appId list of special permission failed." + e);
798         }
799     }
800 
801     /** Should only be used by unit tests */
802     @VisibleForTesting
getVpnUidRanges(String iface)803     public Set<UidRange> getVpnUidRanges(String iface) {
804         return mVpnUidRanges.get(iface);
805     }
806 
onSettingChanged()807     private synchronized void onSettingChanged() {
808         // Step1. Update uids allowed to use restricted networks and compute the set of uids to
809         // update.
810         final Set<Integer> uidsToUpdate = new ArraySet<>(mUidsAllowedOnRestrictedNetworks);
811         updateUidsAllowedOnRestrictedNetworks(mDeps.getUidsAllowedOnRestrictedNetworks(mContext));
812         uidsToUpdate.addAll(mUidsAllowedOnRestrictedNetworks);
813 
814         final Map<Integer, Boolean> updatedUids = new HashMap<>();
815         final Map<Integer, Boolean> removedUids = new HashMap<>();
816 
817         // Step2. For each uid to update, find out its new permission.
818         for (Integer uid : uidsToUpdate) {
819             final Boolean permission = highestUidNetworkPermission(uid);
820 
821             final int appId = UserHandle.getAppId(uid);
822             if (null == permission) {
823                 removedUids.put(appId, NETWORK); // Doesn't matter which permission is set here.
824                 mApps.remove(appId);
825             } else {
826                 updatedUids.put(appId, permission);
827                 mApps.put(appId, permission);
828             }
829         }
830 
831         // Step3. Update or revoke permission for uids with netd.
832         update(mUsers, updatedUids, true /* add */);
833         update(mUsers, removedUids, false /* add */);
834     }
835 
onExternalApplicationsAvailable(String[] pkgList)836     private synchronized void onExternalApplicationsAvailable(String[] pkgList) {
837         if (CollectionUtils.isEmpty(pkgList)) {
838             Log.e(TAG, "No available external application.");
839             return;
840         }
841 
842         for (String app : pkgList) {
843             final PackageInfo info = getPackageInfo(app);
844             if (info == null || info.applicationInfo == null) continue;
845 
846             final int appId = info.applicationInfo.uid;
847             onPackageAdded(app, appId); // Use onPackageAdded to add package one by one.
848         }
849     }
850 
851     /** Dump info to dumpsys */
dump(IndentingPrintWriter pw)852     public void dump(IndentingPrintWriter pw) {
853         pw.println("Interface filtering rules:");
854         pw.increaseIndent();
855         for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
856             pw.println("Interface: " + vpn.getKey());
857             pw.println("UIDs: " + vpn.getValue().toString());
858             pw.println();
859         }
860         pw.decreaseIndent();
861     }
862 
log(String s)863     private static void log(String s) {
864         if (DBG) {
865             Log.d(TAG, s);
866         }
867     }
868 
loge(String s)869     private static void loge(String s) {
870         Log.e(TAG, s);
871     }
872 
loge(String s, Throwable e)873     private static void loge(String s, Throwable e) {
874         Log.e(TAG, s, e);
875     }
876 }
877