• 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.net.ConnectivityManager.FIREWALL_CHAIN_LOCKDOWN_VPN;
27 import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
28 import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
29 import static android.net.ConnectivitySettingsManager.UIDS_ALLOWED_ON_RESTRICTED_NETWORKS;
30 import static android.net.INetd.PERMISSION_INTERNET;
31 import static android.net.INetd.PERMISSION_NETWORK;
32 import static android.net.INetd.PERMISSION_NONE;
33 import static android.net.INetd.PERMISSION_SYSTEM;
34 import static android.net.INetd.PERMISSION_UNINSTALLED;
35 import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS;
36 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
37 import static android.os.Process.INVALID_UID;
38 import static android.os.Process.SYSTEM_UID;
39 
40 import static com.android.net.module.util.CollectionUtils.toIntArray;
41 
42 import android.annotation.NonNull;
43 import android.annotation.Nullable;
44 import android.content.BroadcastReceiver;
45 import android.content.Context;
46 import android.content.Intent;
47 import android.content.IntentFilter;
48 import android.content.pm.ApplicationInfo;
49 import android.content.pm.PackageInfo;
50 import android.content.pm.PackageManager;
51 import android.content.pm.PackageManager.NameNotFoundException;
52 import android.database.ContentObserver;
53 import android.net.ConnectivitySettingsManager;
54 import android.net.INetd;
55 import android.net.UidRange;
56 import android.net.Uri;
57 import android.net.util.SharedLog;
58 import android.os.Build;
59 import android.os.Process;
60 import android.os.RemoteException;
61 import android.os.ServiceSpecificException;
62 import android.os.SystemConfigManager;
63 import android.os.UserHandle;
64 import android.os.UserManager;
65 import android.provider.Settings;
66 import android.util.ArrayMap;
67 import android.util.ArraySet;
68 import android.util.Log;
69 import android.util.SparseIntArray;
70 
71 import com.android.internal.annotations.GuardedBy;
72 import com.android.internal.annotations.VisibleForTesting;
73 import com.android.internal.util.IndentingPrintWriter;
74 import com.android.modules.utils.build.SdkLevel;
75 import com.android.net.module.util.CollectionUtils;
76 import com.android.networkstack.apishim.ProcessShimImpl;
77 import com.android.networkstack.apishim.common.ProcessShim;
78 import com.android.server.BpfNetMaps;
79 
80 import java.util.ArrayList;
81 import java.util.HashSet;
82 import java.util.List;
83 import java.util.Map;
84 import java.util.Set;
85 
86 /**
87  * A utility class to inform Netd of UID permissions.
88  * Does a mass update at boot and then monitors for app install/remove.
89  *
90  * @hide
91  */
92 public class PermissionMonitor {
93     private static final String TAG = "PermissionMonitor";
94     private static final boolean DBG = true;
95     private static final int VERSION_Q = Build.VERSION_CODES.Q;
96 
97     private final PackageManager mPackageManager;
98     private final UserManager mUserManager;
99     private final SystemConfigManager mSystemConfigManager;
100     private final INetd mNetd;
101     private final Dependencies mDeps;
102     private final Context mContext;
103     private final BpfNetMaps mBpfNetMaps;
104 
105     private static final ProcessShim sProcessShim = ProcessShimImpl.newInstance();
106 
107     @GuardedBy("this")
108     private final Set<UserHandle> mUsers = new HashSet<>();
109 
110     // Keys are uids. Values are netd network permissions.
111     @GuardedBy("this")
112     private final SparseIntArray mUidToNetworkPerm = new SparseIntArray();
113 
114     // NonNull keys are active non-bypassable and fully-routed VPN's interface name, Values are uid
115     // ranges for apps under the VPNs which enable interface filtering.
116     // If key is null, Values are uid ranges for apps under the VPNs which are connected but do not
117     // enable interface filtering.
118     @GuardedBy("this")
119     private final Map<String, Set<UidRange>> mVpnInterfaceUidRanges = new ArrayMap<>();
120 
121     // Items are uid ranges for apps under the VPN Lockdown
122     // Ranges were given through ConnectivityManager#setRequireVpnForUids, and ranges are allowed to
123     // have duplicates. Also, it is allowed to give ranges that are already subject to lockdown.
124     // So we need to maintain uid range with multiset.
125     @GuardedBy("this")
126     private final MultiSet<UidRange> mVpnLockdownUidRanges = new MultiSet<>();
127 
128     // A set of appIds for apps across all users on the device. We track appIds instead of uids
129     // directly to reduce its size and also eliminate the need to update this set when user is
130     // added/removed.
131     @GuardedBy("this")
132     private final Set<Integer> mAllApps = new HashSet<>();
133 
134     // A set of uids which are allowed to use restricted networks. The packages of these uids can't
135     // hold the CONNECTIVITY_USE_RESTRICTED_NETWORKS permission because they can't be
136     // signature|privileged apps. However, these apps should still be able to use restricted
137     // networks under certain conditions (e.g. government app using emergency services). So grant
138     // netd system permission to these uids which is listed in UIDS_ALLOWED_ON_RESTRICTED_NETWORKS.
139     @GuardedBy("this")
140     private final Set<Integer> mUidsAllowedOnRestrictedNetworks = new ArraySet<>();
141 
142     // Store PackageManager for each user.
143     // Keys are users, Values are PackageManagers which get from each user.
144     @GuardedBy("this")
145     private final Map<UserHandle, PackageManager> mUsersPackageManager = new ArrayMap<>();
146 
147     // Store appIds traffic permissions for each user.
148     // Keys are users, Values are SparseArrays where each entry maps an appId to the permissions
149     // that appId has within that user. The permissions are a bitmask of PERMISSION_INTERNET and
150     // PERMISSION_UPDATE_DEVICE_STATS, or 0 (PERMISSION_NONE) if the app has neither of those
151     // permissions. They can never be PERMISSION_UNINSTALLED.
152     @GuardedBy("this")
153     private final Map<UserHandle, SparseIntArray> mUsersTrafficPermissions = new ArrayMap<>();
154 
155     private static final int SYSTEM_APPID = SYSTEM_UID;
156 
157     private static final int MAX_PERMISSION_UPDATE_LOGS = 40;
158     private final SharedLog mPermissionUpdateLogs = new SharedLog(MAX_PERMISSION_UPDATE_LOGS, TAG);
159 
160     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
161         @Override
162         public void onReceive(Context context, Intent intent) {
163             final String action = intent.getAction();
164 
165             if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
166                 final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
167                 final Uri packageData = intent.getData();
168                 final String packageName =
169                         packageData != null ? packageData.getSchemeSpecificPart() : null;
170                 onPackageAdded(packageName, uid);
171             } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
172                 final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
173                 final Uri packageData = intent.getData();
174                 final String packageName =
175                         packageData != null ? packageData.getSchemeSpecificPart() : null;
176                 onPackageRemoved(packageName, uid);
177             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
178                 final String[] pkgList =
179                         intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
180                 onExternalApplicationsAvailable(pkgList);
181             } else {
182                 Log.wtf(TAG, "received unexpected intent: " + action);
183             }
184         }
185     };
186 
187     /**
188      * Dependencies of PermissionMonitor, for injection in tests.
189      */
190     @VisibleForTesting
191     public static class Dependencies {
192         /**
193          * Get device first sdk version.
194          */
getDeviceFirstSdkInt()195         public int getDeviceFirstSdkInt() {
196             return Build.VERSION.DEVICE_INITIAL_SDK_INT;
197         }
198 
199         /**
200          * Get uids allowed to use restricted networks via ConnectivitySettingsManager.
201          */
getUidsAllowedOnRestrictedNetworks(@onNull Context context)202         public Set<Integer> getUidsAllowedOnRestrictedNetworks(@NonNull Context context) {
203             return ConnectivitySettingsManager.getUidsAllowedOnRestrictedNetworks(context);
204         }
205 
206         /**
207          * Register ContentObserver for given Uri.
208          */
registerContentObserver(@onNull Context context, @NonNull Uri uri, boolean notifyForDescendants, @NonNull ContentObserver observer)209         public void registerContentObserver(@NonNull Context context, @NonNull Uri uri,
210                 boolean notifyForDescendants, @NonNull ContentObserver observer) {
211             context.getContentResolver().registerContentObserver(
212                     uri, notifyForDescendants, observer);
213         }
214     }
215 
216     private static class MultiSet<T> {
217         private final Map<T, Integer> mMap = new ArrayMap<>();
218 
219         /**
220          * Returns the number of key in the set before this addition.
221          */
add(T key)222         public int add(T key) {
223             final int oldCount = mMap.getOrDefault(key, 0);
224             mMap.put(key, oldCount + 1);
225             return oldCount;
226         }
227 
228         /**
229          * Return the number of key in the set before this removal.
230          */
remove(T key)231         public int remove(T key) {
232             final int oldCount = mMap.getOrDefault(key, 0);
233             if (oldCount == 0) {
234                 Log.wtf(TAG, "Attempt to remove non existing key = " + key.toString());
235             } else if (oldCount == 1) {
236                 mMap.remove(key);
237             } else {
238                 mMap.put(key, oldCount - 1);
239             }
240             return oldCount;
241         }
242 
getSet()243         public Set<T> getSet() {
244             return mMap.keySet();
245         }
246     }
247 
PermissionMonitor(@onNull final Context context, @NonNull final INetd netd, @NonNull final BpfNetMaps bpfNetMaps)248     public PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd,
249             @NonNull final BpfNetMaps bpfNetMaps) {
250         this(context, netd, bpfNetMaps, new Dependencies());
251     }
252 
253     @VisibleForTesting
PermissionMonitor(@onNull final Context context, @NonNull final INetd netd, @NonNull final BpfNetMaps bpfNetMaps, @NonNull final Dependencies deps)254     PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd,
255             @NonNull final BpfNetMaps bpfNetMaps,
256             @NonNull final Dependencies deps) {
257         mPackageManager = context.getPackageManager();
258         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
259         mSystemConfigManager = context.getSystemService(SystemConfigManager.class);
260         mNetd = netd;
261         mDeps = deps;
262         mContext = context;
263         mBpfNetMaps = bpfNetMaps;
264     }
265 
getPackageNetdNetworkPermission(@onNull final PackageInfo app)266     private int getPackageNetdNetworkPermission(@NonNull final PackageInfo app) {
267         if (hasRestrictedNetworkPermission(app)) {
268             return PERMISSION_SYSTEM;
269         }
270         if (hasNetworkPermission(app)) {
271             return PERMISSION_NETWORK;
272         }
273         return PERMISSION_NONE;
274     }
275 
isHigherNetworkPermission(final int targetPermission, final int currentPermission)276     static boolean isHigherNetworkPermission(final int targetPermission,
277             final int currentPermission) {
278         // This is relied on strict order of network permissions (SYSTEM > NETWORK > NONE), and it
279         // is enforced in tests.
280         return targetPermission > currentPermission;
281     }
282 
getInstalledPackagesAsUser(final UserHandle user)283     private List<PackageInfo> getInstalledPackagesAsUser(final UserHandle user) {
284         return mPackageManager.getInstalledPackagesAsUser(GET_PERMISSIONS, user.getIdentifier());
285     }
286 
updateAllApps(final List<PackageInfo> apps)287     private synchronized void updateAllApps(final List<PackageInfo> apps) {
288         for (PackageInfo app : apps) {
289             final int appId = app.applicationInfo != null
290                     ? UserHandle.getAppId(app.applicationInfo.uid) : INVALID_UID;
291             if (appId < 0) {
292                 continue;
293             }
294             mAllApps.add(appId);
295         }
296     }
297 
hasSdkSandbox(final int uid)298     private static boolean hasSdkSandbox(final int uid) {
299         return SdkLevel.isAtLeastT() && Process.isApplicationUid(uid);
300     }
301 
302     // Return the network permission for the passed list of apps. Note that this depends on the
303     // current settings of the device (See isUidAllowedOnRestrictedNetworks).
makeUidsNetworkPerm(final List<PackageInfo> apps)304     private SparseIntArray makeUidsNetworkPerm(final List<PackageInfo> apps) {
305         final SparseIntArray uidsPerm = new SparseIntArray();
306         for (PackageInfo app : apps) {
307             final int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
308             if (uid < 0) {
309                 continue;
310             }
311             final int permission = getPackageNetdNetworkPermission(app);
312             if (isHigherNetworkPermission(permission, uidsPerm.get(uid, PERMISSION_NONE))) {
313                 uidsPerm.put(uid, permission);
314                 if (hasSdkSandbox(uid)) {
315                     int sdkSandboxUid = sProcessShim.toSdkSandboxUid(uid);
316                     uidsPerm.put(sdkSandboxUid, permission);
317                 }
318             }
319         }
320         return uidsPerm;
321     }
322 
makeAppIdsTrafficPerm(final List<PackageInfo> apps)323     private static SparseIntArray makeAppIdsTrafficPerm(final List<PackageInfo> apps) {
324         final SparseIntArray appIdsPerm = new SparseIntArray();
325         for (PackageInfo app : apps) {
326             final int appId = app.applicationInfo != null
327                     ? UserHandle.getAppId(app.applicationInfo.uid) : INVALID_UID;
328             if (appId < 0) {
329                 continue;
330             }
331             final int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions,
332                     app.requestedPermissionsFlags);
333             final int permission = appIdsPerm.get(appId) | otherNetdPerms;
334             appIdsPerm.put(appId, permission);
335             if (hasSdkSandbox(appId)) {
336                 appIdsPerm.put(sProcessShim.toSdkSandboxUid(appId), permission);
337             }
338         }
339         return appIdsPerm;
340     }
341 
updateUidsNetworkPermission(final SparseIntArray uids)342     private synchronized void updateUidsNetworkPermission(final SparseIntArray uids) {
343         for (int i = 0; i < uids.size(); i++) {
344             mUidToNetworkPerm.put(uids.keyAt(i), uids.valueAt(i));
345         }
346         sendUidsNetworkPermission(uids, true /* add */);
347     }
348 
349     /**
350      * Calculates permissions for appIds.
351      * Maps each appId to the union of all traffic permissions that the appId has in all users.
352      *
353      * @return The appIds traffic permissions.
354      */
makeAppIdsTrafficPermForAllUsers()355     private synchronized SparseIntArray makeAppIdsTrafficPermForAllUsers() {
356         final SparseIntArray appIds = new SparseIntArray();
357         // Check appIds permissions from each user.
358         for (UserHandle user : mUsersTrafficPermissions.keySet()) {
359             final SparseIntArray userAppIds = mUsersTrafficPermissions.get(user);
360             for (int i = 0; i < userAppIds.size(); i++) {
361                 final int appId = userAppIds.keyAt(i);
362                 final int permission = userAppIds.valueAt(i);
363                 appIds.put(appId, appIds.get(appId) | permission);
364             }
365         }
366         return appIds;
367     }
368 
getSystemTrafficPerm()369     private SparseIntArray getSystemTrafficPerm() {
370         final SparseIntArray appIdsPerm = new SparseIntArray();
371         for (final int uid : mSystemConfigManager.getSystemPermissionUids(INTERNET)) {
372             final int appId = UserHandle.getAppId(uid);
373             final int permission = appIdsPerm.get(appId) | PERMISSION_INTERNET;
374             appIdsPerm.put(appId, permission);
375             if (hasSdkSandbox(appId)) {
376                 appIdsPerm.put(sProcessShim.toSdkSandboxUid(appId), permission);
377             }
378         }
379         for (final int uid : mSystemConfigManager.getSystemPermissionUids(UPDATE_DEVICE_STATS)) {
380             final int appId = UserHandle.getAppId(uid);
381             final int permission = appIdsPerm.get(appId) | PERMISSION_UPDATE_DEVICE_STATS;
382             appIdsPerm.put(appId, permission);
383             if (hasSdkSandbox(appId)) {
384                 appIdsPerm.put(sProcessShim.toSdkSandboxUid(appId), permission);
385             }
386         }
387         return appIdsPerm;
388     }
389 
390     // Intended to be called only once at startup, after the system is ready. Installs a broadcast
391     // receiver to monitor ongoing UID changes, so this shouldn't/needn't be called again.
startMonitoring()392     public synchronized void startMonitoring() {
393         log("Monitoring");
394 
395         final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
396         final IntentFilter intentFilter = new IntentFilter();
397         intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
398         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
399         intentFilter.addDataScheme("package");
400         userAllContext.registerReceiver(
401                 mIntentReceiver, intentFilter, null /* broadcastPermission */,
402                 null /* scheduler */);
403 
404         // Listen to EXTERNAL_APPLICATIONS_AVAILABLE is that an app becoming available means it may
405         // need to gain a permission. But an app that becomes unavailable can neither gain nor lose
406         // permissions on that account, it just can no longer run. Thus, doesn't need to listen to
407         // EXTERNAL_APPLICATIONS_UNAVAILABLE.
408         final IntentFilter externalIntentFilter =
409                 new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
410         userAllContext.registerReceiver(
411                 mIntentReceiver, externalIntentFilter, null /* broadcastPermission */,
412                 null /* scheduler */);
413 
414         // Register UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting observer
415         mDeps.registerContentObserver(
416                 userAllContext,
417                 Settings.Global.getUriFor(UIDS_ALLOWED_ON_RESTRICTED_NETWORKS),
418                 false /* notifyForDescendants */,
419                 new ContentObserver(null) {
420                     @Override
421                     public void onChange(boolean selfChange) {
422                         onSettingChanged();
423                     }
424                 });
425 
426         // Read UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting and update
427         // mUidsAllowedOnRestrictedNetworks.
428         updateUidsAllowedOnRestrictedNetworks(mDeps.getUidsAllowedOnRestrictedNetworks(mContext));
429 
430         // Read system traffic permissions when a user removed and put them to USER_ALL because they
431         // are not specific to any particular user.
432         mUsersTrafficPermissions.put(UserHandle.ALL, getSystemTrafficPerm());
433 
434         final List<UserHandle> usrs = mUserManager.getUserHandles(true /* excludeDying */);
435         // Update netd permissions for all users.
436         for (UserHandle user : usrs) {
437             onUserAdded(user);
438         }
439         log("Users: " + mUsers.size() + ", UidToNetworkPerm: " + mUidToNetworkPerm.size());
440     }
441 
442     @VisibleForTesting
updateUidsAllowedOnRestrictedNetworks(final Set<Integer> uids)443     synchronized void updateUidsAllowedOnRestrictedNetworks(final Set<Integer> uids) {
444         mUidsAllowedOnRestrictedNetworks.clear();
445         mUidsAllowedOnRestrictedNetworks.addAll(uids);
446     }
447 
448     @VisibleForTesting
isVendorApp(@onNull ApplicationInfo appInfo)449     static boolean isVendorApp(@NonNull ApplicationInfo appInfo) {
450         return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct();
451     }
452 
453     @VisibleForTesting
isCarryoverPackage(final ApplicationInfo appInfo)454     boolean isCarryoverPackage(final ApplicationInfo appInfo) {
455         if (appInfo == null) return false;
456         return (appInfo.targetSdkVersion < VERSION_Q && isVendorApp(appInfo))
457                 // Backward compatibility for b/114245686, on devices that launched before Q daemons
458                 // and apps running as the system UID are exempted from this check.
459                 || (UserHandle.getAppId(appInfo.uid) == SYSTEM_APPID
460                         && mDeps.getDeviceFirstSdkInt() < VERSION_Q);
461     }
462 
463     @VisibleForTesting
isUidAllowedOnRestrictedNetworks(final ApplicationInfo appInfo)464     synchronized boolean isUidAllowedOnRestrictedNetworks(final ApplicationInfo appInfo) {
465         if (appInfo == null) return false;
466         // Check whether package's uid is in allowed on restricted networks uid list. If so, this
467         // uid can have netd system permission.
468         return isUidAllowedOnRestrictedNetworks(appInfo.uid);
469     }
470 
471     /**
472      * Returns whether the given uid is in allowed on restricted networks list.
473      */
isUidAllowedOnRestrictedNetworks(final int uid)474     public synchronized boolean isUidAllowedOnRestrictedNetworks(final int uid) {
475         return mUidsAllowedOnRestrictedNetworks.contains(uid);
476     }
477 
478     @VisibleForTesting
hasPermission(@onNull final PackageInfo app, @NonNull final String permission)479     boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) {
480         if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
481             return false;
482         }
483         final int index = CollectionUtils.indexOf(app.requestedPermissions, permission);
484         if (index < 0 || index >= app.requestedPermissionsFlags.length) return false;
485         return (app.requestedPermissionsFlags[index] & REQUESTED_PERMISSION_GRANTED) != 0;
486     }
487 
488     @VisibleForTesting
hasNetworkPermission(@onNull final PackageInfo app)489     boolean hasNetworkPermission(@NonNull final PackageInfo app) {
490         return hasPermission(app, CHANGE_NETWORK_STATE);
491     }
492 
493     @VisibleForTesting
hasRestrictedNetworkPermission(@onNull final PackageInfo app)494     boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) {
495         // TODO : remove carryover package check in the future(b/31479477). All apps should just
496         //  request the appropriate permission for their use case since android Q.
497         return isCarryoverPackage(app.applicationInfo)
498                 || isUidAllowedOnRestrictedNetworks(app.applicationInfo)
499                 || hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK)
500                 || hasPermission(app, NETWORK_STACK)
501                 || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
502     }
503 
504     /** Returns whether the given uid has using background network permission. */
hasUseBackgroundNetworksPermission(final int uid)505     public synchronized boolean hasUseBackgroundNetworksPermission(final int uid) {
506         // Apps with any of the CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_INTERNAL or
507         // CONNECTIVITY_USE_RESTRICTED_NETWORKS permission has the permission to use background
508         // networks. mUidToNetworkPerm contains the result of checks for hasNetworkPermission and
509         // hasRestrictedNetworkPermission, as well as the list of UIDs allowed on restricted
510         // networks. If uid is in the mUidToNetworkPerm list that means uid has one of permissions
511         // at least.
512         return mUidToNetworkPerm.get(uid, PERMISSION_NONE) != PERMISSION_NONE;
513     }
514 
515     /**
516      * Returns whether the given uid has permission to use restricted networks.
517      */
hasRestrictedNetworksPermission(int uid)518     public synchronized boolean hasRestrictedNetworksPermission(int uid) {
519         return PERMISSION_SYSTEM == mUidToNetworkPerm.get(uid, PERMISSION_NONE);
520     }
521 
sendUidsNetworkPermission(SparseIntArray uids, boolean add)522     private void sendUidsNetworkPermission(SparseIntArray uids, boolean add) {
523         List<Integer> network = new ArrayList<>();
524         List<Integer> system = new ArrayList<>();
525         for (int i = 0; i < uids.size(); i++) {
526             final int permission = uids.valueAt(i);
527             if (PERMISSION_NONE == permission) {
528                 continue; // Normally NONE is not stored in this map, but just in case
529             }
530             List<Integer> list = (PERMISSION_SYSTEM == permission) ? system : network;
531             list.add(uids.keyAt(i));
532         }
533         try {
534             if (add) {
535                 mNetd.networkSetPermissionForUser(PERMISSION_NETWORK, toIntArray(network));
536                 mNetd.networkSetPermissionForUser(PERMISSION_SYSTEM, toIntArray(system));
537             } else {
538                 mNetd.networkClearPermissionForUser(toIntArray(network));
539                 mNetd.networkClearPermissionForUser(toIntArray(system));
540             }
541         } catch (RemoteException e) {
542             loge("Exception when updating permissions: " + e);
543         }
544     }
545 
546     /**
547      * Called when a user is added. See {link #ACTION_USER_ADDED}.
548      *
549      * @param user The integer userHandle of the added user. See {@link #EXTRA_USER_HANDLE}.
550      *
551      * @hide
552      */
onUserAdded(@onNull UserHandle user)553     public synchronized void onUserAdded(@NonNull UserHandle user) {
554         mUsers.add(user);
555 
556         final List<PackageInfo> apps = getInstalledPackagesAsUser(user);
557 
558         // Save all apps
559         updateAllApps(apps);
560 
561         // Uids network permissions
562         final SparseIntArray uids = makeUidsNetworkPerm(apps);
563         updateUidsNetworkPermission(uids);
564 
565         // Add new user appIds permissions.
566         final SparseIntArray addedUserAppIds = makeAppIdsTrafficPerm(apps);
567         mUsersTrafficPermissions.put(user, addedUserAppIds);
568         // Generate appIds from all users and send result to netd.
569         final SparseIntArray appIds = makeAppIdsTrafficPermForAllUsers();
570         sendAppIdsTrafficPermission(appIds);
571 
572         // Log user added
573         mPermissionUpdateLogs.log("New user(" + user.getIdentifier() + ") added: nPerm uids="
574                 + uids + ", tPerm appIds=" + addedUserAppIds);
575     }
576 
577     /**
578      * Called when an user is removed. See {link #ACTION_USER_REMOVED}.
579      *
580      * @param user The integer userHandle of the removed user. See {@link #EXTRA_USER_HANDLE}.
581      *
582      * @hide
583      */
onUserRemoved(@onNull UserHandle user)584     public synchronized void onUserRemoved(@NonNull UserHandle user) {
585         mUsers.remove(user);
586 
587         // Remove uids network permissions that belongs to the user.
588         final SparseIntArray removedUids = new SparseIntArray();
589         final SparseIntArray allUids = mUidToNetworkPerm.clone();
590         for (int i = 0; i < allUids.size(); i++) {
591             final int uid = allUids.keyAt(i);
592             if (user.equals(UserHandle.getUserHandleForUid(uid))) {
593                 mUidToNetworkPerm.delete(uid);
594                 removedUids.put(uid, allUids.valueAt(i));
595             }
596         }
597         sendUidsNetworkPermission(removedUids, false /* add */);
598 
599         // Remove appIds traffic permission that belongs to the user
600         final SparseIntArray removedUserAppIds = mUsersTrafficPermissions.remove(user);
601         // Generate appIds from the remaining users.
602         final SparseIntArray appIds = makeAppIdsTrafficPermForAllUsers();
603 
604         if (removedUserAppIds == null) {
605             Log.wtf(TAG, "onUserRemoved: Receive unknown user=" + user);
606             return;
607         }
608 
609         // Clear permission on those appIds belong to this user only, set the permission to
610         // PERMISSION_UNINSTALLED.
611         for (int i = 0; i < removedUserAppIds.size(); i++) {
612             final int appId = removedUserAppIds.keyAt(i);
613             // Need to clear permission if the removed appId is not found in the array.
614             if (appIds.indexOfKey(appId) < 0) {
615                 appIds.put(appId, PERMISSION_UNINSTALLED);
616             }
617         }
618         sendAppIdsTrafficPermission(appIds);
619 
620         // Log user removed
621         mPermissionUpdateLogs.log("User(" + user.getIdentifier() + ") removed: nPerm uids="
622                 + removedUids + ", tPerm appIds=" + removedUserAppIds);
623     }
624 
625     /**
626      * Compare the current network permission and the given package's permission to find out highest
627      * permission for the uid.
628      *
629      * @param uid The target uid
630      * @param currentPermission Current uid network permission
631      * @param name The package has same uid that need compare its permission to update uid network
632      *             permission.
633      */
634     @VisibleForTesting
highestPermissionForUid(int uid, int currentPermission, String name)635     protected int highestPermissionForUid(int uid, int currentPermission, String name) {
636         // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
637         // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
638         if (currentPermission == PERMISSION_SYSTEM) {
639             return currentPermission;
640         }
641         final PackageInfo app = getPackageInfoAsUser(name, UserHandle.getUserHandleForUid(uid));
642         if (app == null) return currentPermission;
643 
644         final int permission = getPackageNetdNetworkPermission(app);
645         if (isHigherNetworkPermission(permission, currentPermission)) {
646             return permission;
647         }
648         return currentPermission;
649     }
650 
getTrafficPermissionForUid(final int uid)651     private int getTrafficPermissionForUid(final int uid) {
652         int permission = PERMISSION_NONE;
653         // Check all the packages for this UID. The UID has the permission if any of the
654         // packages in it has the permission.
655         final String[] packages = mPackageManager.getPackagesForUid(uid);
656         if (packages != null && packages.length > 0) {
657             for (String name : packages) {
658                 final PackageInfo app = getPackageInfoAsUser(name,
659                         UserHandle.getUserHandleForUid(uid));
660                 if (app != null && app.requestedPermissions != null) {
661                     permission |= getNetdPermissionMask(app.requestedPermissions,
662                             app.requestedPermissionsFlags);
663                 }
664             }
665         } else {
666             // The last package of this uid is removed from device. Clean the package up.
667             permission = PERMISSION_UNINSTALLED;
668         }
669         return permission;
670     }
671 
updateVpnUid(int uid, boolean add)672     private synchronized void updateVpnUid(int uid, boolean add) {
673         // Apps that can use restricted networks can always bypass VPNs.
674         if (hasRestrictedNetworksPermission(uid)) {
675             return;
676         }
677         for (Map.Entry<String, Set<UidRange>> vpn : mVpnInterfaceUidRanges.entrySet()) {
678             if (UidRange.containsUid(vpn.getValue(), uid)) {
679                 final Set<Integer> changedUids = new HashSet<>();
680                 changedUids.add(uid);
681                 updateVpnUidsInterfaceRules(vpn.getKey(), changedUids, add);
682             }
683         }
684     }
685 
updateLockdownUid(int uid, boolean add)686     private synchronized void updateLockdownUid(int uid, boolean add) {
687         if (UidRange.containsUid(mVpnLockdownUidRanges.getSet(), uid)
688                 && !hasRestrictedNetworksPermission(uid)) {
689             updateLockdownUidRule(uid, add);
690         }
691     }
692 
693     /**
694      * This handles both network and traffic permission, because there is no overlap in actual
695      * values, where network permission is NETWORK or SYSTEM, and traffic permission is INTERNET
696      * or UPDATE_DEVICE_STATS
697      */
permissionToString(int permission)698     private String permissionToString(int permission) {
699         switch (permission) {
700             case PERMISSION_NONE:
701                 return "NONE";
702             case PERMISSION_NETWORK:
703                 return "NETWORK";
704             case PERMISSION_SYSTEM:
705                 return "SYSTEM";
706             case PERMISSION_INTERNET:
707                 return "INTERNET";
708             case PERMISSION_UPDATE_DEVICE_STATS:
709                 return "UPDATE_DEVICE_STATS";
710             case (PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS):
711                 return "ALL";
712             case PERMISSION_UNINSTALLED:
713                 return "UNINSTALLED";
714             default:
715                 return "UNKNOWN";
716         }
717     }
718 
updateAppIdTrafficPermission(int uid)719     private synchronized void updateAppIdTrafficPermission(int uid) {
720         final int uidTrafficPerm = getTrafficPermissionForUid(uid);
721         final SparseIntArray userTrafficPerms =
722                 mUsersTrafficPermissions.get(UserHandle.getUserHandleForUid(uid));
723         if (userTrafficPerms == null) {
724             Log.wtf(TAG, "Can't get user traffic permission from uid=" + uid);
725             return;
726         }
727         // Do not put PERMISSION_UNINSTALLED into the array. If no package left on the uid
728         // (PERMISSION_UNINSTALLED), remove the appId from the array. Otherwise, update the latest
729         // permission to the appId.
730         final int appId = UserHandle.getAppId(uid);
731         if (uidTrafficPerm == PERMISSION_UNINSTALLED) {
732             userTrafficPerms.delete(appId);
733         } else {
734             userTrafficPerms.put(appId, uidTrafficPerm);
735         }
736     }
737 
getAppIdTrafficPermission(int appId)738     private synchronized int getAppIdTrafficPermission(int appId) {
739         int permission = PERMISSION_NONE;
740         boolean installed = false;
741         for (UserHandle user : mUsersTrafficPermissions.keySet()) {
742             final SparseIntArray userApps = mUsersTrafficPermissions.get(user);
743             final int appIdx = userApps.indexOfKey(appId);
744             if (appIdx >= 0) {
745                 permission |= userApps.valueAt(appIdx);
746                 installed = true;
747             }
748         }
749         return installed ? permission : PERMISSION_UNINSTALLED;
750     }
751 
752     /**
753      * Called when a package is added.
754      *
755      * @param packageName The name of the new package.
756      * @param uid The uid of the new package.
757      *
758      * @hide
759      */
onPackageAdded(@onNull final String packageName, final int uid)760     public synchronized void onPackageAdded(@NonNull final String packageName, final int uid) {
761         // Update uid permission.
762         updateAppIdTrafficPermission(uid);
763         // Get the appId permission from all users then send the latest permission to netd.
764         final int appId = UserHandle.getAppId(uid);
765         final int appIdTrafficPerm = getAppIdTrafficPermission(appId);
766         sendPackagePermissionsForAppId(appId, appIdTrafficPerm);
767 
768         final int currentPermission = mUidToNetworkPerm.get(uid, PERMISSION_NONE);
769         final int permission = highestPermissionForUid(uid, currentPermission, packageName);
770         if (permission != currentPermission) {
771             mUidToNetworkPerm.put(uid, permission);
772 
773             SparseIntArray apps = new SparseIntArray();
774             apps.put(uid, permission);
775 
776             if (hasSdkSandbox(uid)) {
777                 int sdkSandboxUid = sProcessShim.toSdkSandboxUid(uid);
778                 mUidToNetworkPerm.put(sdkSandboxUid, permission);
779                 apps.put(sdkSandboxUid, permission);
780             }
781             sendUidsNetworkPermission(apps, true /* add */);
782         }
783 
784         // If the newly-installed package falls within some VPN's uid range, update Netd with it.
785         // This needs to happen after the mUidToNetworkPerm update above, since
786         // hasRestrictedNetworksPermission() in updateVpnUid() and updateLockdownUid() depends on
787         // mUidToNetworkPerm to check if the package can bypass VPN.
788         updateVpnUid(uid, true /* add */);
789         updateLockdownUid(uid, true /* add */);
790         mAllApps.add(appId);
791 
792         // Log package added.
793         mPermissionUpdateLogs.log("Package add: name=" + packageName + ", uid=" + uid
794                 + ", nPerm=(" + permissionToString(permission) + "/"
795                 + permissionToString(currentPermission) + ")"
796                 + ", tPerm=" + permissionToString(appIdTrafficPerm));
797     }
798 
highestUidNetworkPermission(int uid)799     private int highestUidNetworkPermission(int uid) {
800         int permission = PERMISSION_NONE;
801         final String[] packages = mPackageManager.getPackagesForUid(uid);
802         if (!CollectionUtils.isEmpty(packages)) {
803             for (String name : packages) {
804                 // If multiple packages have the same UID, give the UID all permissions that
805                 // any package in that UID has.
806                 permission = highestPermissionForUid(uid, permission, name);
807                 if (permission == PERMISSION_SYSTEM) {
808                     break;
809                 }
810             }
811         }
812         return permission;
813     }
814 
815     /**
816      * Called when a package is removed.
817      *
818      * @param packageName The name of the removed package or null.
819      * @param uid containing the integer uid previously assigned to the package.
820      *
821      * @hide
822      */
onPackageRemoved(@onNull final String packageName, final int uid)823     public synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) {
824         // Update uid permission.
825         updateAppIdTrafficPermission(uid);
826         // Get the appId permission from all users then send the latest permission to netd.
827         final int appId = UserHandle.getAppId(uid);
828         final int appIdTrafficPerm = getAppIdTrafficPermission(appId);
829         sendPackagePermissionsForAppId(appId, appIdTrafficPerm);
830 
831         // If the newly-removed package falls within some VPN's uid range, update Netd with it.
832         // This needs to happen before the mUidToNetworkPerm update below, since
833         // hasRestrictedNetworksPermission() in updateVpnUid() and updateLockdownUid() depends on
834         // mUidToNetworkPerm to check if the package can bypass VPN.
835         updateVpnUid(uid, false /* add */);
836         updateLockdownUid(uid, false /* add */);
837         // If the package has been removed from all users on the device, clear it form mAllApps.
838         if (mPackageManager.getNameForUid(uid) == null) {
839             mAllApps.remove(appId);
840         }
841 
842         final int currentPermission = mUidToNetworkPerm.get(uid, PERMISSION_NONE);
843         final int permission = highestUidNetworkPermission(uid);
844 
845         // Log package removed.
846         mPermissionUpdateLogs.log("Package remove: name=" + packageName + ", uid=" + uid
847                 + ", nPerm=(" + permissionToString(permission) + "/"
848                 + permissionToString(currentPermission) + ")"
849                 + ", tPerm=" + permissionToString(appIdTrafficPerm));
850 
851         if (permission != currentPermission) {
852             final SparseIntArray apps = new SparseIntArray();
853             int sdkSandboxUid = -1;
854             if (hasSdkSandbox(uid)) {
855                 sdkSandboxUid = sProcessShim.toSdkSandboxUid(uid);
856             }
857             if (permission == PERMISSION_NONE) {
858                 mUidToNetworkPerm.delete(uid);
859                 apps.put(uid, PERMISSION_NETWORK);  // doesn't matter which permission we pick here
860                 if (sdkSandboxUid != -1) {
861                     mUidToNetworkPerm.delete(sdkSandboxUid);
862                     apps.put(sdkSandboxUid, PERMISSION_NETWORK);
863                 }
864                 sendUidsNetworkPermission(apps, false);
865             } else {
866                 mUidToNetworkPerm.put(uid, permission);
867                 apps.put(uid, permission);
868                 if (sdkSandboxUid != -1) {
869                     mUidToNetworkPerm.put(sdkSandboxUid, permission);
870                     apps.put(sdkSandboxUid, permission);
871                 }
872                 sendUidsNetworkPermission(apps, true);
873             }
874         }
875     }
876 
getNetdPermissionMask(String[] requestedPermissions, int[] requestedPermissionsFlags)877     private static int getNetdPermissionMask(String[] requestedPermissions,
878                                              int[] requestedPermissionsFlags) {
879         int permissions = PERMISSION_NONE;
880         if (requestedPermissions == null || requestedPermissionsFlags == null) return permissions;
881         for (int i = 0; i < requestedPermissions.length; i++) {
882             if (requestedPermissions[i].equals(INTERNET)
883                     && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
884                 permissions |= PERMISSION_INTERNET;
885             }
886             if (requestedPermissions[i].equals(UPDATE_DEVICE_STATS)
887                     && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
888                 permissions |= PERMISSION_UPDATE_DEVICE_STATS;
889             }
890         }
891         return permissions;
892     }
893 
getPackageManagerAsUser(UserHandle user)894     private synchronized PackageManager getPackageManagerAsUser(UserHandle user) {
895         PackageManager pm = mUsersPackageManager.get(user);
896         if (pm == null) {
897             pm = mContext.createContextAsUser(user, 0 /* flag */).getPackageManager();
898             mUsersPackageManager.put(user, pm);
899         }
900         return pm;
901     }
902 
getPackageInfoAsUser(String packageName, UserHandle user)903     private PackageInfo getPackageInfoAsUser(String packageName, UserHandle user) {
904         try {
905             final PackageInfo info = getPackageManagerAsUser(user)
906                     .getPackageInfo(packageName, GET_PERMISSIONS);
907             return info;
908         } catch (NameNotFoundException e) {
909             // App not found.
910             loge("NameNotFoundException " + packageName);
911             return null;
912         }
913     }
914 
915     /**
916      * Called when a new set of UID ranges are added to an active VPN network
917      *
918      * @param iface The active VPN network's interface name. Null iface indicates that the app is
919      *              allowed to receive packets on all interfaces.
920      * @param rangesToAdd The new UID ranges to be added to the network
921      * @param vpnAppUid The uid of the VPN app
922      */
onVpnUidRangesAdded(@ullable String iface, Set<UidRange> rangesToAdd, int vpnAppUid)923     public synchronized void onVpnUidRangesAdded(@Nullable String iface, Set<UidRange> rangesToAdd,
924             int vpnAppUid) {
925         // Calculate the list of new app uids under the VPN due to the new UID ranges and update
926         // Netd about them. Because mAllApps only contains appIds instead of uids, the result might
927         // be an overestimation if an app is not installed on the user on which the VPN is running,
928         // but that's safe: if an app is not installed, it cannot receive any packets, so dropping
929         // packets to that UID is fine.
930         final Set<Integer> changedUids = intersectUids(rangesToAdd, mAllApps);
931         removeBypassingUids(changedUids, vpnAppUid);
932         updateVpnUidsInterfaceRules(iface, changedUids, true /* add */);
933         if (mVpnInterfaceUidRanges.containsKey(iface)) {
934             mVpnInterfaceUidRanges.get(iface).addAll(rangesToAdd);
935         } else {
936             mVpnInterfaceUidRanges.put(iface, new HashSet<UidRange>(rangesToAdd));
937         }
938     }
939 
940     /**
941      * Called when a set of UID ranges are removed from an active VPN network
942      *
943      * @param iface The VPN network's interface name. Null iface indicates that the app is allowed
944      *              to receive packets on all interfaces.
945      * @param rangesToRemove Existing UID ranges to be removed from the VPN network
946      * @param vpnAppUid The uid of the VPN app
947      */
onVpnUidRangesRemoved(@ullable String iface, Set<UidRange> rangesToRemove, int vpnAppUid)948     public synchronized void onVpnUidRangesRemoved(@Nullable String iface,
949             Set<UidRange> rangesToRemove, int vpnAppUid) {
950         // Calculate the list of app uids that are no longer under the VPN due to the removed UID
951         // ranges and update Netd about them.
952         final Set<Integer> changedUids = intersectUids(rangesToRemove, mAllApps);
953         removeBypassingUids(changedUids, vpnAppUid);
954         updateVpnUidsInterfaceRules(iface, changedUids, false /* add */);
955         Set<UidRange> existingRanges = mVpnInterfaceUidRanges.getOrDefault(iface, null);
956         if (existingRanges == null) {
957             loge("Attempt to remove unknown vpn uid Range iface = " + iface);
958             return;
959         }
960         existingRanges.removeAll(rangesToRemove);
961         if (existingRanges.size() == 0) {
962             mVpnInterfaceUidRanges.remove(iface);
963         }
964     }
965 
966     /**
967      * Called when UID ranges under VPN Lockdown are updated
968      *
969      * @param add {@code true} if the uids are to be added to the Lockdown, {@code false} if they
970      *        are to be removed from the Lockdown.
971      * @param ranges The updated UID ranges under VPN Lockdown. This function does not treat the VPN
972      *               app's UID in any special way. The caller is responsible for excluding the VPN
973      *               app UID from the passed-in ranges.
974      *               Ranges can have duplications and/or contain the range that is already subject
975      *               to lockdown. However, ranges can not have overlaps with other ranges including
976      *               ranges that are currently subject to lockdown.
977      */
updateVpnLockdownUidRanges(boolean add, UidRange[] ranges)978     public synchronized void updateVpnLockdownUidRanges(boolean add, UidRange[] ranges) {
979         final Set<UidRange> affectedUidRanges = new HashSet<>();
980 
981         for (final UidRange range : ranges) {
982             if (add) {
983                 // Rule will be added if mVpnLockdownUidRanges does not have this uid range entry
984                 // currently.
985                 if (mVpnLockdownUidRanges.add(range) == 0) {
986                     affectedUidRanges.add(range);
987                 }
988             } else {
989                 // Rule will be removed if the number of the range in the set is 1 before the
990                 // removal.
991                 if (mVpnLockdownUidRanges.remove(range) == 1) {
992                     affectedUidRanges.add(range);
993                 }
994             }
995         }
996 
997         // mAllApps only contains appIds instead of uids. So the generated uid list might contain
998         // apps that are installed only on some users but not others. But that's safe: if an app is
999         // not installed, it cannot receive any packets, so dropping packets to that UID is fine.
1000         final Set<Integer> affectedUids = intersectUids(affectedUidRanges, mAllApps);
1001 
1002         // We skip adding rule to privileged apps and allow them to bypass incoming packet
1003         // filtering. The behaviour is consistent with how lockdown works for outgoing packets, but
1004         // the implementation is different: while ConnectivityService#setRequireVpnForUids does not
1005         // exclude privileged apps from the prohibit routing rules used to implement outgoing packet
1006         // filtering, privileged apps can still bypass outgoing packet filtering because the
1007         // prohibit rules observe the protected from VPN bit.
1008         for (final int uid: affectedUids) {
1009             if (!hasRestrictedNetworksPermission(uid)) {
1010                 updateLockdownUidRule(uid, add);
1011             }
1012         }
1013     }
1014 
1015     /**
1016      * Compute the intersection of a set of UidRanges and appIds. Returns a set of uids
1017      * that satisfies:
1018      *   1. falls into one of the UidRange
1019      *   2. matches one of the appIds
1020      */
intersectUids(Set<UidRange> ranges, Set<Integer> appIds)1021     private Set<Integer> intersectUids(Set<UidRange> ranges, Set<Integer> appIds) {
1022         Set<Integer> result = new HashSet<>();
1023         for (UidRange range : ranges) {
1024             for (int userId = range.getStartUser(); userId <= range.getEndUser(); userId++) {
1025                 for (int appId : appIds) {
1026                     final UserHandle handle = UserHandle.of(userId);
1027                     if (handle == null) continue;
1028 
1029                     final int uid = handle.getUid(appId);
1030                     if (range.contains(uid)) {
1031                         result.add(uid);
1032                     }
1033                 }
1034             }
1035         }
1036         return result;
1037     }
1038 
1039     /**
1040      * Remove all apps which can elect to bypass the VPN from the list of uids
1041      *
1042      * An app can elect to bypass the VPN if it holds SYSTEM permission, or if it's the active VPN
1043      * app itself.
1044      *
1045      * @param uids The list of uids to operate on
1046      * @param vpnAppUid The uid of the VPN app
1047      */
removeBypassingUids(Set<Integer> uids, int vpnAppUid)1048     private void removeBypassingUids(Set<Integer> uids, int vpnAppUid) {
1049         uids.remove(vpnAppUid);
1050         uids.removeIf(this::hasRestrictedNetworksPermission);
1051     }
1052 
1053     /**
1054      * Update netd about the list of uids that are under an active VPN connection which they cannot
1055      * bypass.
1056      *
1057      * This is to instruct netd to set up appropriate filtering rules for these uids, such that they
1058      * can only receive ingress packets from the VPN's tunnel interface (and loopback).
1059      * Null iface set up a wildcard rule that allow app to receive packets on all interfaces.
1060      *
1061      * @param iface the interface name of the active VPN connection
1062      * @param add {@code true} if the uids are to be added to the interface, {@code false} if they
1063      *        are to be removed from the interface.
1064      */
updateVpnUidsInterfaceRules(String iface, Set<Integer> uids, boolean add)1065     private void updateVpnUidsInterfaceRules(String iface, Set<Integer> uids, boolean add) {
1066         if (uids.size() == 0) {
1067             return;
1068         }
1069         try {
1070             if (add) {
1071                 mBpfNetMaps.addUidInterfaceRules(iface, toIntArray(uids));
1072             } else {
1073                 mBpfNetMaps.removeUidInterfaceRules(toIntArray(uids));
1074             }
1075         } catch (RemoteException | ServiceSpecificException e) {
1076             loge("Exception when updating permissions: ", e);
1077         }
1078     }
1079 
updateLockdownUidRule(int uid, boolean add)1080     private void updateLockdownUidRule(int uid, boolean add) {
1081         try {
1082             if (add) {
1083                 mBpfNetMaps.setUidRule(FIREWALL_CHAIN_LOCKDOWN_VPN, uid, FIREWALL_RULE_DENY);
1084             } else {
1085                 mBpfNetMaps.setUidRule(FIREWALL_CHAIN_LOCKDOWN_VPN, uid, FIREWALL_RULE_ALLOW);
1086             }
1087         } catch (ServiceSpecificException e) {
1088             loge("Failed to " + (add ? "add" : "remove") + " Lockdown rule: " + e);
1089         }
1090     }
1091 
1092     /**
1093      * Send the updated permission information to netd. Called upon package install/uninstall.
1094      *
1095      * @param appId the appId of the package installed
1096      * @param permissions the permissions the app requested and netd cares about.
1097      *
1098      * @hide
1099      */
1100     @VisibleForTesting
sendPackagePermissionsForAppId(int appId, int permissions)1101     void sendPackagePermissionsForAppId(int appId, int permissions) {
1102         SparseIntArray netdPermissionsAppIds = new SparseIntArray();
1103         netdPermissionsAppIds.put(appId, permissions);
1104         if (hasSdkSandbox(appId)) {
1105             int sdkSandboxAppId = sProcessShim.toSdkSandboxUid(appId);
1106             netdPermissionsAppIds.put(sdkSandboxAppId, permissions);
1107         }
1108         sendAppIdsTrafficPermission(netdPermissionsAppIds);
1109     }
1110 
1111     /**
1112      * Grant or revoke the INTERNET and/or UPDATE_DEVICE_STATS permission of the appIds in array.
1113      *
1114      * @param netdPermissionsAppIds integer pairs of appIds and the permission granted to it. If the
1115      * permission is 0, revoke all permissions of that appId.
1116      *
1117      * @hide
1118      */
1119     @VisibleForTesting
sendAppIdsTrafficPermission(SparseIntArray netdPermissionsAppIds)1120     void sendAppIdsTrafficPermission(SparseIntArray netdPermissionsAppIds) {
1121         final ArrayList<Integer> allPermissionAppIds = new ArrayList<>();
1122         final ArrayList<Integer> internetPermissionAppIds = new ArrayList<>();
1123         final ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
1124         final ArrayList<Integer> noPermissionAppIds = new ArrayList<>();
1125         final ArrayList<Integer> uninstalledAppIds = new ArrayList<>();
1126         for (int i = 0; i < netdPermissionsAppIds.size(); i++) {
1127             int permissions = netdPermissionsAppIds.valueAt(i);
1128             switch(permissions) {
1129                 case (PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS):
1130                     allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
1131                     break;
1132                 case PERMISSION_INTERNET:
1133                     internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
1134                     break;
1135                 case PERMISSION_UPDATE_DEVICE_STATS:
1136                     updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
1137                     break;
1138                 case PERMISSION_NONE:
1139                     noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
1140                     break;
1141                 case PERMISSION_UNINSTALLED:
1142                     uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
1143                     break;
1144                 default:
1145                     Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
1146                             + netdPermissionsAppIds.keyAt(i));
1147             }
1148         }
1149         try {
1150             // TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids()
1151             if (allPermissionAppIds.size() != 0) {
1152                 mBpfNetMaps.setNetPermForUids(
1153                         PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS,
1154                         toIntArray(allPermissionAppIds));
1155             }
1156             if (internetPermissionAppIds.size() != 0) {
1157                 mBpfNetMaps.setNetPermForUids(PERMISSION_INTERNET,
1158                         toIntArray(internetPermissionAppIds));
1159             }
1160             if (updateStatsPermissionAppIds.size() != 0) {
1161                 mBpfNetMaps.setNetPermForUids(PERMISSION_UPDATE_DEVICE_STATS,
1162                         toIntArray(updateStatsPermissionAppIds));
1163             }
1164             if (noPermissionAppIds.size() != 0) {
1165                 mBpfNetMaps.setNetPermForUids(PERMISSION_NONE,
1166                         toIntArray(noPermissionAppIds));
1167             }
1168             if (uninstalledAppIds.size() != 0) {
1169                 mBpfNetMaps.setNetPermForUids(PERMISSION_UNINSTALLED,
1170                         toIntArray(uninstalledAppIds));
1171             }
1172         } catch (RemoteException | ServiceSpecificException e) {
1173             Log.e(TAG, "Pass appId list of special permission failed." + e);
1174         }
1175     }
1176 
1177     /** Should only be used by unit tests */
1178     @VisibleForTesting
getVpnInterfaceUidRanges(String iface)1179     public Set<UidRange> getVpnInterfaceUidRanges(String iface) {
1180         return mVpnInterfaceUidRanges.get(iface);
1181     }
1182 
1183     /** Should only be used by unit tests */
1184     @VisibleForTesting
getVpnLockdownUidRanges()1185     public Set<UidRange> getVpnLockdownUidRanges() {
1186         return mVpnLockdownUidRanges.getSet();
1187     }
1188 
onSettingChanged()1189     private synchronized void onSettingChanged() {
1190         // Step1. Update uids allowed to use restricted networks and compute the set of uids to
1191         // update.
1192         final Set<Integer> uidsToUpdate = new ArraySet<>(mUidsAllowedOnRestrictedNetworks);
1193         updateUidsAllowedOnRestrictedNetworks(mDeps.getUidsAllowedOnRestrictedNetworks(mContext));
1194         uidsToUpdate.addAll(mUidsAllowedOnRestrictedNetworks);
1195 
1196         final SparseIntArray updatedUids = new SparseIntArray();
1197         final SparseIntArray removedUids = new SparseIntArray();
1198 
1199         // Step2. For each uid to update, find out its new permission.
1200         for (Integer uid : uidsToUpdate) {
1201             final int permission = highestUidNetworkPermission(uid);
1202 
1203             if (PERMISSION_NONE == permission) {
1204                 // Doesn't matter which permission is set here.
1205                 removedUids.put(uid, PERMISSION_NETWORK);
1206                 mUidToNetworkPerm.delete(uid);
1207                 if (hasSdkSandbox(uid)) {
1208                     int sdkSandboxUid = sProcessShim.toSdkSandboxUid(uid);
1209                     removedUids.put(sdkSandboxUid, PERMISSION_NETWORK);
1210                     mUidToNetworkPerm.delete(sdkSandboxUid);
1211                 }
1212             } else {
1213                 updatedUids.put(uid, permission);
1214                 mUidToNetworkPerm.put(uid, permission);
1215                 if (hasSdkSandbox(uid)) {
1216                     int sdkSandboxUid = sProcessShim.toSdkSandboxUid(uid);
1217                     updatedUids.put(sdkSandboxUid, permission);
1218                     mUidToNetworkPerm.put(sdkSandboxUid, permission);
1219                 }
1220             }
1221         }
1222 
1223         // Step3. Update or revoke permission for uids with netd.
1224         sendUidsNetworkPermission(updatedUids, true /* add */);
1225         sendUidsNetworkPermission(removedUids, false /* add */);
1226         mPermissionUpdateLogs.log("Setting change: update=" + updatedUids
1227                 + ", remove=" + removedUids);
1228     }
1229 
onExternalApplicationsAvailable(String[] pkgList)1230     private synchronized void onExternalApplicationsAvailable(String[] pkgList) {
1231         if (CollectionUtils.isEmpty(pkgList)) {
1232             Log.e(TAG, "No available external application.");
1233             return;
1234         }
1235 
1236         for (String app : pkgList) {
1237             for (UserHandle user : mUsers) {
1238                 final PackageInfo info = getPackageInfoAsUser(app, user);
1239                 if (info == null || info.applicationInfo == null) continue;
1240 
1241                 final int uid = info.applicationInfo.uid;
1242                 onPackageAdded(app, uid); // Use onPackageAdded to add package one by one.
1243             }
1244         }
1245     }
1246 
1247     /** Dump info to dumpsys */
dump(IndentingPrintWriter pw)1248     public void dump(IndentingPrintWriter pw) {
1249         pw.println("Interface filtering rules:");
1250         pw.increaseIndent();
1251         for (Map.Entry<String, Set<UidRange>> vpn : mVpnInterfaceUidRanges.entrySet()) {
1252             pw.println("Interface: " + vpn.getKey());
1253             pw.println("UIDs: " + vpn.getValue().toString());
1254             pw.println();
1255         }
1256         pw.decreaseIndent();
1257 
1258         pw.println();
1259         pw.println("Lockdown filtering rules:");
1260         pw.increaseIndent();
1261         for (final UidRange range : mVpnLockdownUidRanges.getSet()) {
1262             pw.println("UIDs: " + range.toString());
1263         }
1264         pw.decreaseIndent();
1265 
1266         pw.println();
1267         pw.println("Update logs:");
1268         pw.increaseIndent();
1269         mPermissionUpdateLogs.reverseDump(pw);
1270         pw.decreaseIndent();
1271     }
1272 
log(String s)1273     private static void log(String s) {
1274         if (DBG) {
1275             Log.d(TAG, s);
1276         }
1277     }
1278 
loge(String s)1279     private static void loge(String s) {
1280         Log.e(TAG, s);
1281     }
1282 
loge(String s, Throwable e)1283     private static void loge(String s, Throwable e) {
1284         Log.e(TAG, s, e);
1285     }
1286 }
1287