• 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_INTERNAL;
21 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
22 import static android.Manifest.permission.INTERNET;
23 import static android.Manifest.permission.NETWORK_STACK;
24 import static android.Manifest.permission.UPDATE_DEVICE_STATS;
25 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
26 import static android.content.pm.PackageManager.GET_PERMISSIONS;
27 import static android.content.pm.PackageManager.MATCH_ANY_USER;
28 import static android.os.Process.INVALID_UID;
29 import static android.os.Process.SYSTEM_UID;
30 
31 import android.annotation.NonNull;
32 import android.content.Context;
33 import android.content.pm.ApplicationInfo;
34 import android.content.pm.PackageInfo;
35 import android.content.pm.PackageManager;
36 import android.content.pm.PackageManager.NameNotFoundException;
37 import android.content.pm.PackageManagerInternal;
38 import android.content.pm.UserInfo;
39 import android.net.INetd;
40 import android.net.UidRange;
41 import android.os.Build;
42 import android.os.RemoteException;
43 import android.os.ServiceSpecificException;
44 import android.os.UserHandle;
45 import android.os.UserManager;
46 import android.system.OsConstants;
47 import android.util.ArraySet;
48 import android.util.Log;
49 import android.util.SparseArray;
50 import android.util.SparseIntArray;
51 
52 import com.android.internal.annotations.GuardedBy;
53 import com.android.internal.annotations.VisibleForTesting;
54 import com.android.internal.util.ArrayUtils;
55 import com.android.internal.util.IndentingPrintWriter;
56 import com.android.server.LocalServices;
57 import com.android.server.SystemConfig;
58 
59 import java.util.ArrayList;
60 import java.util.Collection;
61 import java.util.HashMap;
62 import java.util.HashSet;
63 import java.util.List;
64 import java.util.Map;
65 import java.util.Map.Entry;
66 import java.util.Set;
67 
68 
69 /**
70  * A utility class to inform Netd of UID permisisons.
71  * Does a mass update at boot and then monitors for app install/remove.
72  *
73  * @hide
74  */
75 public class PermissionMonitor {
76     private static final String TAG = "PermissionMonitor";
77     private static final boolean DBG = true;
78     protected static final Boolean SYSTEM = Boolean.TRUE;
79     protected static final Boolean NETWORK = Boolean.FALSE;
80     private static final int VERSION_Q = Build.VERSION_CODES.Q;
81 
82     private final PackageManager mPackageManager;
83     private final UserManager mUserManager;
84     private final INetd mNetd;
85 
86     // Values are User IDs.
87     @GuardedBy("this")
88     private final Set<Integer> mUsers = new HashSet<>();
89 
90     // Keys are app uids. Values are true for SYSTEM permission and false for NETWORK permission.
91     @GuardedBy("this")
92     private final Map<Integer, Boolean> mApps = new HashMap<>();
93 
94     // Keys are active non-bypassable and fully-routed VPN's interface name, Values are uid ranges
95     // for apps under the VPN
96     @GuardedBy("this")
97     private final Map<String, Set<UidRange>> mVpnUidRanges = new HashMap<>();
98 
99     // A set of appIds for apps across all users on the device. We track appIds instead of uids
100     // directly to reduce its size and also eliminate the need to update this set when user is
101     // added/removed.
102     @GuardedBy("this")
103     private final Set<Integer> mAllApps = new HashSet<>();
104 
105     private class PackageListObserver implements PackageManagerInternal.PackageListObserver {
106 
getPermissionForUid(int uid)107         private int getPermissionForUid(int uid) {
108             int permission = 0;
109             // Check all the packages for this UID. The UID has the permission if any of the
110             // packages in it has the permission.
111             String[] packages = mPackageManager.getPackagesForUid(uid);
112             if (packages != null && packages.length > 0) {
113                 for (String name : packages) {
114                     final PackageInfo app = getPackageInfo(name);
115                     if (app != null && app.requestedPermissions != null) {
116                         permission |= getNetdPermissionMask(app.requestedPermissions,
117                               app.requestedPermissionsFlags);
118                     }
119                 }
120             } else {
121                 // The last package of this uid is removed from device. Clean the package up.
122                 permission = INetd.PERMISSION_UNINSTALLED;
123             }
124             return permission;
125         }
126 
127         @Override
onPackageAdded(String packageName, int uid)128         public void onPackageAdded(String packageName, int uid) {
129             sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
130         }
131 
132         @Override
onPackageRemoved(String packageName, int uid)133         public void onPackageRemoved(String packageName, int uid) {
134             sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
135         }
136     }
137 
PermissionMonitor(Context context, INetd netd)138     public PermissionMonitor(Context context, INetd netd) {
139         mPackageManager = context.getPackageManager();
140         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
141         mNetd = netd;
142     }
143 
144     // Intended to be called only once at startup, after the system is ready. Installs a broadcast
145     // receiver to monitor ongoing UID changes, so this shouldn't/needn't be called again.
startMonitoring()146     public synchronized void startMonitoring() {
147         log("Monitoring");
148 
149         PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
150         if (pmi != null) {
151             pmi.getPackageList(new PackageListObserver());
152         } else {
153             loge("failed to get the PackageManagerInternal service");
154         }
155         List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
156                 | MATCH_ANY_USER);
157         if (apps == null) {
158             loge("No apps");
159             return;
160         }
161 
162         SparseIntArray netdPermsUids = new SparseIntArray();
163 
164         for (PackageInfo app : apps) {
165             int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
166             if (uid < 0) {
167                 continue;
168             }
169             mAllApps.add(UserHandle.getAppId(uid));
170 
171             boolean isNetwork = hasNetworkPermission(app);
172             boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
173 
174             if (isNetwork || hasRestrictedPermission) {
175                 Boolean permission = mApps.get(uid);
176                 // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
177                 // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
178                 if (permission == null || permission == NETWORK) {
179                     mApps.put(uid, hasRestrictedPermission);
180                 }
181             }
182 
183             //TODO: unify the management of the permissions into one codepath.
184             int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions,
185                     app.requestedPermissionsFlags);
186             netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
187         }
188 
189         List<UserInfo> users = mUserManager.getUsers(true);  // exclude dying users
190         if (users != null) {
191             for (UserInfo user : users) {
192                 mUsers.add(user.id);
193             }
194         }
195 
196         final SparseArray<ArraySet<String>> systemPermission =
197                 SystemConfig.getInstance().getSystemPermissions();
198         for (int i = 0; i < systemPermission.size(); i++) {
199             ArraySet<String> perms = systemPermission.valueAt(i);
200             int uid = systemPermission.keyAt(i);
201             int netdPermission = 0;
202             // Get the uids of native services that have UPDATE_DEVICE_STATS or INTERNET permission.
203             if (perms != null) {
204                 netdPermission |= perms.contains(UPDATE_DEVICE_STATS)
205                         ? INetd.PERMISSION_UPDATE_DEVICE_STATS : 0;
206                 netdPermission |= perms.contains(INTERNET)
207                         ? INetd.PERMISSION_INTERNET : 0;
208             }
209             netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
210         }
211         log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
212         update(mUsers, mApps, true);
213         sendPackagePermissionsToNetd(netdPermsUids);
214     }
215 
216     @VisibleForTesting
isVendorApp(@onNull ApplicationInfo appInfo)217     static boolean isVendorApp(@NonNull ApplicationInfo appInfo) {
218         return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct();
219     }
220 
221     @VisibleForTesting
getDeviceFirstSdkInt()222     protected int getDeviceFirstSdkInt() {
223         return Build.VERSION.FIRST_SDK_INT;
224     }
225 
226     @VisibleForTesting
hasPermission(@onNull final PackageInfo app, @NonNull final String permission)227     boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) {
228         if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
229             return false;
230         }
231         final int index = ArrayUtils.indexOf(app.requestedPermissions, permission);
232         if (index < 0 || index >= app.requestedPermissionsFlags.length) return false;
233         return (app.requestedPermissionsFlags[index] & REQUESTED_PERMISSION_GRANTED) != 0;
234     }
235 
236     @VisibleForTesting
hasNetworkPermission(@onNull final PackageInfo app)237     boolean hasNetworkPermission(@NonNull final PackageInfo app) {
238         return hasPermission(app, CHANGE_NETWORK_STATE);
239     }
240 
241     @VisibleForTesting
hasRestrictedNetworkPermission(@onNull final PackageInfo app)242     boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) {
243         // TODO : remove this check in the future(b/31479477). All apps should just
244         // request the appropriate permission for their use case since android Q.
245         if (app.applicationInfo != null) {
246             // Backward compatibility for b/114245686, on devices that launched before Q daemons
247             // and apps running as the system UID are exempted from this check.
248             if (app.applicationInfo.uid == SYSTEM_UID && getDeviceFirstSdkInt() < VERSION_Q) {
249                 return true;
250             }
251 
252             if (app.applicationInfo.targetSdkVersion < VERSION_Q
253                     && isVendorApp(app.applicationInfo)) {
254                 return true;
255             }
256         }
257         return hasPermission(app, CONNECTIVITY_INTERNAL)
258                 || hasPermission(app, NETWORK_STACK)
259                 || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
260     }
261 
262     /** Returns whether the given uid has using background network permission. */
hasUseBackgroundNetworksPermission(final int uid)263     public synchronized boolean hasUseBackgroundNetworksPermission(final int uid) {
264         // Apps with any of the CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_INTERNAL or
265         // CONNECTIVITY_USE_RESTRICTED_NETWORKS permission has the permission to use background
266         // networks. mApps contains the result of checks for both hasNetworkPermission and
267         // hasRestrictedNetworkPermission. If uid is in the mApps list that means uid has one of
268         // permissions at least.
269         return mApps.containsKey(uid);
270     }
271 
toIntArray(Collection<Integer> list)272     private int[] toIntArray(Collection<Integer> list) {
273         int[] array = new int[list.size()];
274         int i = 0;
275         for (Integer item : list) {
276             array[i++] = item;
277         }
278         return array;
279     }
280 
update(Set<Integer> users, Map<Integer, Boolean> apps, boolean add)281     private void update(Set<Integer> users, Map<Integer, Boolean> apps, boolean add) {
282         List<Integer> network = new ArrayList<>();
283         List<Integer> system = new ArrayList<>();
284         for (Entry<Integer, Boolean> app : apps.entrySet()) {
285             List<Integer> list = app.getValue() ? system : network;
286             for (int user : users) {
287                 list.add(UserHandle.getUid(user, app.getKey()));
288             }
289         }
290         try {
291             if (add) {
292                 mNetd.networkSetPermissionForUser(INetd.PERMISSION_NETWORK, toIntArray(network));
293                 mNetd.networkSetPermissionForUser(INetd.PERMISSION_SYSTEM, toIntArray(system));
294             } else {
295                 mNetd.networkClearPermissionForUser(toIntArray(network));
296                 mNetd.networkClearPermissionForUser(toIntArray(system));
297             }
298         } catch (RemoteException e) {
299             loge("Exception when updating permissions: " + e);
300         }
301     }
302 
303     /**
304      * Called when a user is added. See {link #ACTION_USER_ADDED}.
305      *
306      * @param user The integer userHandle of the added user. See {@link #EXTRA_USER_HANDLE}.
307      *
308      * @hide
309      */
onUserAdded(int user)310     public synchronized void onUserAdded(int user) {
311         if (user < 0) {
312             loge("Invalid user in onUserAdded: " + user);
313             return;
314         }
315         mUsers.add(user);
316 
317         Set<Integer> users = new HashSet<>();
318         users.add(user);
319         update(users, mApps, true);
320     }
321 
322     /**
323      * Called when an user is removed. See {link #ACTION_USER_REMOVED}.
324      *
325      * @param user The integer userHandle of the removed user. See {@link #EXTRA_USER_HANDLE}.
326      *
327      * @hide
328      */
onUserRemoved(int user)329     public synchronized void onUserRemoved(int user) {
330         if (user < 0) {
331             loge("Invalid user in onUserRemoved: " + user);
332             return;
333         }
334         mUsers.remove(user);
335 
336         Set<Integer> users = new HashSet<>();
337         users.add(user);
338         update(users, mApps, false);
339     }
340 
341     @VisibleForTesting
highestPermissionForUid(Boolean currentPermission, String name)342     protected Boolean highestPermissionForUid(Boolean currentPermission, String name) {
343         if (currentPermission == SYSTEM) {
344             return currentPermission;
345         }
346         try {
347             final PackageInfo app = mPackageManager.getPackageInfo(name, GET_PERMISSIONS);
348             final boolean isNetwork = hasNetworkPermission(app);
349             final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
350             if (isNetwork || hasRestrictedPermission) {
351                 currentPermission = hasRestrictedPermission;
352             }
353         } catch (NameNotFoundException e) {
354             // App not found.
355             loge("NameNotFoundException " + name);
356         }
357         return currentPermission;
358     }
359 
360     /**
361      * Called when a package is added. See {link #ACTION_PACKAGE_ADDED}.
362      *
363      * @param packageName The name of the new package.
364      * @param uid The uid of the new package.
365      *
366      * @hide
367      */
onPackageAdded(String packageName, int uid)368     public synchronized void onPackageAdded(String packageName, int uid) {
369         // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
370         // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
371         final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName);
372         if (permission != mApps.get(uid)) {
373             mApps.put(uid, permission);
374 
375             Map<Integer, Boolean> apps = new HashMap<>();
376             apps.put(uid, permission);
377             update(mUsers, apps, true);
378         }
379 
380         // If the newly-installed package falls within some VPN's uid range, update Netd with it.
381         // This needs to happen after the mApps update above, since removeBypassingUids() depends
382         // on mApps to check if the package can bypass VPN.
383         for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
384             if (UidRange.containsUid(vpn.getValue(), uid)) {
385                 final Set<Integer> changedUids = new HashSet<>();
386                 changedUids.add(uid);
387                 removeBypassingUids(changedUids, /* vpnAppUid */ -1);
388                 updateVpnUids(vpn.getKey(), changedUids, true);
389             }
390         }
391         mAllApps.add(UserHandle.getAppId(uid));
392     }
393 
394     /**
395      * Called when a package is removed. See {link #ACTION_PACKAGE_REMOVED}.
396      *
397      * @param uid containing the integer uid previously assigned to the package.
398      *
399      * @hide
400      */
onPackageRemoved(int uid)401     public synchronized void onPackageRemoved(int uid) {
402         // If the newly-removed package falls within some VPN's uid range, update Netd with it.
403         // This needs to happen before the mApps update below, since removeBypassingUids() depends
404         // on mApps to check if the package can bypass VPN.
405         for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
406             if (UidRange.containsUid(vpn.getValue(), uid)) {
407                 final Set<Integer> changedUids = new HashSet<>();
408                 changedUids.add(uid);
409                 removeBypassingUids(changedUids, /* vpnAppUid */ -1);
410                 updateVpnUids(vpn.getKey(), changedUids, false);
411             }
412         }
413         // If the package has been removed from all users on the device, clear it form mAllApps.
414         if (mPackageManager.getNameForUid(uid) == null) {
415             mAllApps.remove(UserHandle.getAppId(uid));
416         }
417 
418         Map<Integer, Boolean> apps = new HashMap<>();
419         Boolean permission = null;
420         String[] packages = mPackageManager.getPackagesForUid(uid);
421         if (packages != null && packages.length > 0) {
422             for (String name : packages) {
423                 permission = highestPermissionForUid(permission, name);
424                 if (permission == SYSTEM) {
425                     // An app with this UID still has the SYSTEM permission.
426                     // Therefore, this UID must already have the SYSTEM permission.
427                     // Nothing to do.
428                     return;
429                 }
430             }
431         }
432         if (permission == mApps.get(uid)) {
433             // The permissions of this UID have not changed. Nothing to do.
434             return;
435         } else if (permission != null) {
436             mApps.put(uid, permission);
437             apps.put(uid, permission);
438             update(mUsers, apps, true);
439         } else {
440             mApps.remove(uid);
441             apps.put(uid, NETWORK);  // doesn't matter which permission we pick here
442             update(mUsers, apps, false);
443         }
444     }
445 
getNetdPermissionMask(String[] requestedPermissions, int[] requestedPermissionsFlags)446     private static int getNetdPermissionMask(String[] requestedPermissions,
447                                              int[] requestedPermissionsFlags) {
448         int permissions = 0;
449         if (requestedPermissions == null || requestedPermissionsFlags == null) return permissions;
450         for (int i = 0; i < requestedPermissions.length; i++) {
451             if (requestedPermissions[i].equals(INTERNET)
452                     && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
453                 permissions |= INetd.PERMISSION_INTERNET;
454             }
455             if (requestedPermissions[i].equals(UPDATE_DEVICE_STATS)
456                     && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
457                 permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS;
458             }
459         }
460         return permissions;
461     }
462 
getPackageInfo(String packageName)463     private PackageInfo getPackageInfo(String packageName) {
464         try {
465             PackageInfo app = mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS
466                     | MATCH_ANY_USER);
467             return app;
468         } catch (NameNotFoundException e) {
469             return null;
470         }
471     }
472 
473     /**
474      * Called when a new set of UID ranges are added to an active VPN network
475      *
476      * @param iface The active VPN network's interface name
477      * @param rangesToAdd The new UID ranges to be added to the network
478      * @param vpnAppUid The uid of the VPN app
479      */
onVpnUidRangesAdded(@onNull String iface, Set<UidRange> rangesToAdd, int vpnAppUid)480     public synchronized void onVpnUidRangesAdded(@NonNull String iface, Set<UidRange> rangesToAdd,
481             int vpnAppUid) {
482         // Calculate the list of new app uids under the VPN due to the new UID ranges and update
483         // Netd about them. Because mAllApps only contains appIds instead of uids, the result might
484         // be an overestimation if an app is not installed on the user on which the VPN is running,
485         // but that's safe.
486         final Set<Integer> changedUids = intersectUids(rangesToAdd, mAllApps);
487         removeBypassingUids(changedUids, vpnAppUid);
488         updateVpnUids(iface, changedUids, true);
489         if (mVpnUidRanges.containsKey(iface)) {
490             mVpnUidRanges.get(iface).addAll(rangesToAdd);
491         } else {
492             mVpnUidRanges.put(iface, new HashSet<UidRange>(rangesToAdd));
493         }
494     }
495 
496     /**
497      * Called when a set of UID ranges are removed from an active VPN network
498      *
499      * @param iface The VPN network's interface name
500      * @param rangesToRemove Existing UID ranges to be removed from the VPN network
501      * @param vpnAppUid The uid of the VPN app
502      */
onVpnUidRangesRemoved(@onNull String iface, Set<UidRange> rangesToRemove, int vpnAppUid)503     public synchronized void onVpnUidRangesRemoved(@NonNull String iface,
504             Set<UidRange> rangesToRemove, int vpnAppUid) {
505         // Calculate the list of app uids that are no longer under the VPN due to the removed UID
506         // ranges and update Netd about them.
507         final Set<Integer> changedUids = intersectUids(rangesToRemove, mAllApps);
508         removeBypassingUids(changedUids, vpnAppUid);
509         updateVpnUids(iface, changedUids, false);
510         Set<UidRange> existingRanges = mVpnUidRanges.getOrDefault(iface, null);
511         if (existingRanges == null) {
512             loge("Attempt to remove unknown vpn uid Range iface = " + iface);
513             return;
514         }
515         existingRanges.removeAll(rangesToRemove);
516         if (existingRanges.size() == 0) {
517             mVpnUidRanges.remove(iface);
518         }
519     }
520 
521     /**
522      * Compute the intersection of a set of UidRanges and appIds. Returns a set of uids
523      * that satisfies:
524      *   1. falls into one of the UidRange
525      *   2. matches one of the appIds
526      */
intersectUids(Set<UidRange> ranges, Set<Integer> appIds)527     private Set<Integer> intersectUids(Set<UidRange> ranges, Set<Integer> appIds) {
528         Set<Integer> result = new HashSet<>();
529         for (UidRange range : ranges) {
530             for (int userId = range.getStartUser(); userId <= range.getEndUser(); userId++) {
531                 for (int appId : appIds) {
532                     final int uid = UserHandle.getUid(userId, appId);
533                     if (range.contains(uid)) {
534                         result.add(uid);
535                     }
536                 }
537             }
538         }
539         return result;
540     }
541 
542     /**
543      * Remove all apps which can elect to bypass the VPN from the list of uids
544      *
545      * An app can elect to bypass the VPN if it hold SYSTEM permission, or if its the active VPN
546      * app itself.
547      *
548      * @param uids The list of uids to operate on
549      * @param vpnAppUid The uid of the VPN app
550      */
removeBypassingUids(Set<Integer> uids, int vpnAppUid)551     private void removeBypassingUids(Set<Integer> uids, int vpnAppUid) {
552         uids.remove(vpnAppUid);
553         uids.removeIf(uid -> mApps.getOrDefault(uid, NETWORK) == SYSTEM);
554     }
555 
556     /**
557      * Update netd about the list of uids that are under an active VPN connection which they cannot
558      * bypass.
559      *
560      * This is to instruct netd to set up appropriate filtering rules for these uids, such that they
561      * can only receive ingress packets from the VPN's tunnel interface (and loopback).
562      *
563      * @param iface the interface name of the active VPN connection
564      * @param add {@code true} if the uids are to be added to the interface, {@code false} if they
565      *        are to be removed from the interface.
566      */
updateVpnUids(String iface, Set<Integer> uids, boolean add)567     private void updateVpnUids(String iface, Set<Integer> uids, boolean add) {
568         if (uids.size() == 0) {
569             return;
570         }
571         try {
572             if (add) {
573                 mNetd.firewallAddUidInterfaceRules(iface, toIntArray(uids));
574             } else {
575                 mNetd.firewallRemoveUidInterfaceRules(toIntArray(uids));
576             }
577         } catch (ServiceSpecificException e) {
578             // Silently ignore exception when device does not support eBPF, otherwise just log
579             // the exception and do not crash
580             if (e.errorCode != OsConstants.EOPNOTSUPP) {
581                 loge("Exception when updating permissions: ", e);
582             }
583         } catch (RemoteException e) {
584             loge("Exception when updating permissions: ", e);
585         }
586     }
587 
588     /**
589      * Called by PackageListObserver when a package is installed/uninstalled. Send the updated
590      * permission information to netd.
591      *
592      * @param uid the app uid of the package installed
593      * @param permissions the permissions the app requested and netd cares about.
594      *
595      * @hide
596      */
597     @VisibleForTesting
sendPackagePermissionsForUid(int uid, int permissions)598     void sendPackagePermissionsForUid(int uid, int permissions) {
599         SparseIntArray netdPermissionsAppIds = new SparseIntArray();
600         netdPermissionsAppIds.put(uid, permissions);
601         sendPackagePermissionsToNetd(netdPermissionsAppIds);
602     }
603 
604     /**
605      * Called by packageManagerService to send IPC to netd. Grant or revoke the INTERNET
606      * and/or UPDATE_DEVICE_STATS permission of the uids in array.
607      *
608      * @param netdPermissionsAppIds integer pairs of uids and the permission granted to it. If the
609      * permission is 0, revoke all permissions of that uid.
610      *
611      * @hide
612      */
613     @VisibleForTesting
sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds)614     void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
615         if (mNetd == null) {
616             Log.e(TAG, "Failed to get the netd service");
617             return;
618         }
619         ArrayList<Integer> allPermissionAppIds = new ArrayList<>();
620         ArrayList<Integer> internetPermissionAppIds = new ArrayList<>();
621         ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
622         ArrayList<Integer> noPermissionAppIds = new ArrayList<>();
623         ArrayList<Integer> uninstalledAppIds = new ArrayList<>();
624         for (int i = 0; i < netdPermissionsAppIds.size(); i++) {
625             int permissions = netdPermissionsAppIds.valueAt(i);
626             switch(permissions) {
627                 case (INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS):
628                     allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
629                     break;
630                 case INetd.PERMISSION_INTERNET:
631                     internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
632                     break;
633                 case INetd.PERMISSION_UPDATE_DEVICE_STATS:
634                     updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
635                     break;
636                 case INetd.PERMISSION_NONE:
637                     noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
638                     break;
639                 case INetd.PERMISSION_UNINSTALLED:
640                     uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
641                 default:
642                     Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
643                             + netdPermissionsAppIds.keyAt(i));
644             }
645         }
646         try {
647             // TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids()
648             if (allPermissionAppIds.size() != 0) {
649                 mNetd.trafficSetNetPermForUids(
650                         INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
651                         ArrayUtils.convertToIntArray(allPermissionAppIds));
652             }
653             if (internetPermissionAppIds.size() != 0) {
654                 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
655                         ArrayUtils.convertToIntArray(internetPermissionAppIds));
656             }
657             if (updateStatsPermissionAppIds.size() != 0) {
658                 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
659                         ArrayUtils.convertToIntArray(updateStatsPermissionAppIds));
660             }
661             if (noPermissionAppIds.size() != 0) {
662                 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE,
663                         ArrayUtils.convertToIntArray(noPermissionAppIds));
664             }
665             if (uninstalledAppIds.size() != 0) {
666                 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UNINSTALLED,
667                         ArrayUtils.convertToIntArray(uninstalledAppIds));
668             }
669         } catch (RemoteException e) {
670             Log.e(TAG, "Pass appId list of special permission failed." + e);
671         }
672     }
673 
674     /** Should only be used by unit tests */
675     @VisibleForTesting
getVpnUidRanges(String iface)676     public Set<UidRange> getVpnUidRanges(String iface) {
677         return mVpnUidRanges.get(iface);
678     }
679 
680     /** Dump info to dumpsys */
dump(IndentingPrintWriter pw)681     public void dump(IndentingPrintWriter pw) {
682         pw.println("Interface filtering rules:");
683         pw.increaseIndent();
684         for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
685             pw.println("Interface: " + vpn.getKey());
686             pw.println("UIDs: " + vpn.getValue().toString());
687             pw.println();
688         }
689         pw.decreaseIndent();
690     }
691 
log(String s)692     private static void log(String s) {
693         if (DBG) {
694             Log.d(TAG, s);
695         }
696     }
697 
loge(String s)698     private static void loge(String s) {
699         Log.e(TAG, s);
700     }
701 
loge(String s, Throwable e)702     private static void loge(String s, Throwable e) {
703         Log.e(TAG, s, e);
704     }
705 }
706