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