blob: f0b7150dd84ff31699afc655012a3ef130a63df4 [file] [log] [blame]
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -07001/*
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
17package com.android.server.connectivity;
18
19import static android.Manifest.permission.CHANGE_NETWORK_STATE;
Hugo Benichi514da602016-07-19 15:59:27 +090020import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
Chenbo Fenge16cd662019-01-07 16:14:26 -080021import static android.Manifest.permission.INTERNET;
Chalard Jean26aa91a2018-03-20 19:13:57 +090022import static android.Manifest.permission.NETWORK_STACK;
Chenbo Fenge16cd662019-01-07 16:14:26 -080023import static android.Manifest.permission.UPDATE_DEVICE_STATS;
Chenbo Fengdc179822019-03-08 11:55:12 -080024import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070025import static android.content.pm.PackageManager.GET_PERMISSIONS;
Chenbo Fenge16cd662019-01-07 16:14:26 -080026import static android.content.pm.PackageManager.MATCH_ANY_USER;
paulhu59148b72019-08-12 16:25:11 +080027import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
paulhu3b0f5ea2018-11-01 10:38:11 +080028import static android.os.Process.INVALID_UID;
29import static android.os.Process.SYSTEM_UID;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070030
paulhub6733802018-08-20 11:01:21 +080031import android.annotation.NonNull;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070032import android.content.Context;
Chalard Jean26aa91a2018-03-20 19:13:57 +090033import android.content.pm.ApplicationInfo;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070034import android.content.pm.PackageInfo;
35import android.content.pm.PackageManager;
36import android.content.pm.PackageManager.NameNotFoundException;
Chenbo Fenge16cd662019-01-07 16:14:26 -080037import android.content.pm.PackageManagerInternal;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070038import android.content.pm.UserInfo;
Chenbo Fenge16cd662019-01-07 16:14:26 -080039import android.net.INetd;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000040import android.net.UidRange;
paulhub6733802018-08-20 11:01:21 +080041import android.os.Build;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070042import android.os.RemoteException;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000043import android.os.ServiceSpecificException;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070044import android.os.UserHandle;
45import android.os.UserManager;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000046import android.system.OsConstants;
Chenbo Fengdd77fce2019-03-26 14:36:34 -070047import android.util.ArraySet;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070048import android.util.Log;
Chenbo Fengdd77fce2019-03-26 14:36:34 -070049import android.util.SparseArray;
Chenbo Fenge16cd662019-01-07 16:14:26 -080050import android.util.SparseIntArray;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070051
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000052import com.android.internal.annotations.GuardedBy;
Chalard Jean26aa91a2018-03-20 19:13:57 +090053import com.android.internal.annotations.VisibleForTesting;
Chenbo Fenge16cd662019-01-07 16:14:26 -080054import com.android.internal.util.ArrayUtils;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000055import com.android.internal.util.IndentingPrintWriter;
Chenbo Fenge16cd662019-01-07 16:14:26 -080056import com.android.server.LocalServices;
Chenbo Fengdd77fce2019-03-26 14:36:34 -070057import com.android.server.SystemConfig;
Chalard Jean26aa91a2018-03-20 19:13:57 +090058
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070059import java.util.ArrayList;
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000060import java.util.Collection;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070061import java.util.HashMap;
62import java.util.HashSet;
63import java.util.List;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070064import java.util.Map;
Chenbo Fenge16cd662019-01-07 16:14:26 -080065import java.util.Map.Entry;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070066import java.util.Set;
67
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000068
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070069/**
70 * A utility class to inform Netd of UID permisisons.
71 * Does a mass update at boot and then monitors for app install/remove.
72 *
73 * @hide
74 */
75public class PermissionMonitor {
76 private static final String TAG = "PermissionMonitor";
77 private static final boolean DBG = true;
junyulai2454b692018-11-01 17:16:31 +080078 protected static final Boolean SYSTEM = Boolean.TRUE;
79 protected static final Boolean NETWORK = Boolean.FALSE;
paulhu3b0f5ea2018-11-01 10:38:11 +080080 private static final int VERSION_Q = Build.VERSION_CODES.Q;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070081
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070082 private final PackageManager mPackageManager;
83 private final UserManager mUserManager;
Chenbo Feng436fe582019-02-25 22:55:58 -080084 private final INetd mNetd;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070085
86 // Values are User IDs.
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000087 @GuardedBy("this")
Hugo Benichi514da602016-07-19 15:59:27 +090088 private final Set<Integer> mUsers = new HashSet<>();
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070089
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000090 // Keys are app uids. Values are true for SYSTEM permission and false for NETWORK permission.
91 @GuardedBy("this")
Hugo Benichi514da602016-07-19 15:59:27 +090092 private final Map<Integer, Boolean> mApps = new HashMap<>();
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -070093
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +000094 // Keys are active non-bypassable and fully-routed VPN's interface name, Values are uid ranges
95 // for apps under the VPN
96 @GuardedBy("this")
97 private final Map<String, Set<UidRange>> mVpnUidRanges = new HashMap<>();
98
99 // A set of appIds for apps across all users on the device. We track appIds instead of uids
100 // directly to reduce its size and also eliminate the need to update this set when user is
101 // added/removed.
102 @GuardedBy("this")
103 private final Set<Integer> mAllApps = new HashSet<>();
104
Chenbo Fenge16cd662019-01-07 16:14:26 -0800105 private class PackageListObserver implements PackageManagerInternal.PackageListObserver {
Chenbo Fenge16cd662019-01-07 16:14:26 -0800106
Chenbo Fengdc179822019-03-08 11:55:12 -0800107 private int getPermissionForUid(int uid) {
Chenbo Fenge16cd662019-01-07 16:14:26 -0800108 int permission = 0;
Chenbo Fengdc179822019-03-08 11:55:12 -0800109 // Check all the packages for this UID. The UID has the permission if any of the
110 // packages in it has the permission.
Chenbo Fenge16cd662019-01-07 16:14:26 -0800111 String[] packages = mPackageManager.getPackagesForUid(uid);
112 if (packages != null && packages.length > 0) {
113 for (String name : packages) {
114 final PackageInfo app = getPackageInfo(name);
115 if (app != null && app.requestedPermissions != null) {
Chenbo Fengdc179822019-03-08 11:55:12 -0800116 permission |= getNetdPermissionMask(app.requestedPermissions,
117 app.requestedPermissionsFlags);
Chenbo Fenge16cd662019-01-07 16:14:26 -0800118 }
119 }
Chenbo Fenga6817cd2019-03-25 18:13:34 -0700120 } else {
121 // The last package of this uid is removed from device. Clean the package up.
122 permission = INetd.PERMISSION_UNINSTALLED;
Chenbo Fenge16cd662019-01-07 16:14:26 -0800123 }
Chenbo Fengdc179822019-03-08 11:55:12 -0800124 return permission;
125 }
126
127 @Override
128 public void onPackageAdded(String packageName, int uid) {
129 sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
130 }
131
132 @Override
wangmingming171df3da2019-08-14 15:38:22 +0800133 public void onPackageChanged(@NonNull String packageName, int uid) {
134 sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
135 }
136
137 @Override
Chenbo Fengdc179822019-03-08 11:55:12 -0800138 public void onPackageRemoved(String packageName, int uid) {
139 sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
Chenbo Fenge16cd662019-01-07 16:14:26 -0800140 }
141 }
142
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000143 public PermissionMonitor(Context context, INetd netd) {
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700144 mPackageManager = context.getPackageManager();
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000145 mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
146 mNetd = netd;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700147 }
148
149 // Intended to be called only once at startup, after the system is ready. Installs a broadcast
150 // receiver to monitor ongoing UID changes, so this shouldn't/needn't be called again.
151 public synchronized void startMonitoring() {
152 log("Monitoring");
153
Chenbo Fenge16cd662019-01-07 16:14:26 -0800154 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
155 if (pmi != null) {
156 pmi.getPackageList(new PackageListObserver());
157 } else {
158 loge("failed to get the PackageManagerInternal service");
159 }
160 List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
161 | MATCH_ANY_USER);
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700162 if (apps == null) {
163 loge("No apps");
164 return;
165 }
166
Chenbo Fenge16cd662019-01-07 16:14:26 -0800167 SparseIntArray netdPermsUids = new SparseIntArray();
168
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700169 for (PackageInfo app : apps) {
paulhu3b0f5ea2018-11-01 10:38:11 +0800170 int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700171 if (uid < 0) {
172 continue;
173 }
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000174 mAllApps.add(UserHandle.getAppId(uid));
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700175
176 boolean isNetwork = hasNetworkPermission(app);
Hugo Benichi514da602016-07-19 15:59:27 +0900177 boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700178
Hugo Benichi514da602016-07-19 15:59:27 +0900179 if (isNetwork || hasRestrictedPermission) {
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700180 Boolean permission = mApps.get(uid);
181 // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
182 // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
183 if (permission == null || permission == NETWORK) {
Hugo Benichi514da602016-07-19 15:59:27 +0900184 mApps.put(uid, hasRestrictedPermission);
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700185 }
186 }
Chenbo Fenge16cd662019-01-07 16:14:26 -0800187
188 //TODO: unify the management of the permissions into one codepath.
Chenbo Fengdc179822019-03-08 11:55:12 -0800189 int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions,
190 app.requestedPermissionsFlags);
191 netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700192 }
193
194 List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users
195 if (users != null) {
196 for (UserInfo user : users) {
197 mUsers.add(user.id);
198 }
199 }
200
Chenbo Fengdd77fce2019-03-26 14:36:34 -0700201 final SparseArray<ArraySet<String>> systemPermission =
202 SystemConfig.getInstance().getSystemPermissions();
203 for (int i = 0; i < systemPermission.size(); i++) {
204 ArraySet<String> perms = systemPermission.valueAt(i);
205 int uid = systemPermission.keyAt(i);
206 int netdPermission = 0;
Chenbo Fenge5d6f0f2019-05-22 15:28:49 -0700207 // Get the uids of native services that have UPDATE_DEVICE_STATS or INTERNET permission.
Chenbo Fengdd77fce2019-03-26 14:36:34 -0700208 if (perms != null) {
209 netdPermission |= perms.contains(UPDATE_DEVICE_STATS)
210 ? INetd.PERMISSION_UPDATE_DEVICE_STATS : 0;
Chenbo Fenge5d6f0f2019-05-22 15:28:49 -0700211 netdPermission |= perms.contains(INTERNET)
212 ? INetd.PERMISSION_INTERNET : 0;
Chenbo Fengdd77fce2019-03-26 14:36:34 -0700213 }
Chenbo Fengdd77fce2019-03-26 14:36:34 -0700214 netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
215 }
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700216 log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
217 update(mUsers, mApps, true);
Chenbo Fenge16cd662019-01-07 16:14:26 -0800218 sendPackagePermissionsToNetd(netdPermsUids);
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700219 }
220
Chalard Jean26aa91a2018-03-20 19:13:57 +0900221 @VisibleForTesting
paulhub6733802018-08-20 11:01:21 +0800222 static boolean isVendorApp(@NonNull ApplicationInfo appInfo) {
223 return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct();
Chalard Jean26aa91a2018-03-20 19:13:57 +0900224 }
225
226 @VisibleForTesting
junyulai345155e2018-11-09 12:37:16 +0800227 protected int getDeviceFirstSdkInt() {
paulhu3b0f5ea2018-11-01 10:38:11 +0800228 return Build.VERSION.FIRST_SDK_INT;
229 }
230
231 @VisibleForTesting
paulhu86e23eb2019-11-05 18:05:05 +0800232 boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) {
233 if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
234 return false;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700235 }
paulhu86e23eb2019-11-05 18:05:05 +0800236 final int index = ArrayUtils.indexOf(app.requestedPermissions, permission);
237 if (index < 0 || index >= app.requestedPermissionsFlags.length) return false;
238 return (app.requestedPermissionsFlags[index] & REQUESTED_PERMISSION_GRANTED) != 0;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700239 }
240
paulhu86e23eb2019-11-05 18:05:05 +0800241 @VisibleForTesting
242 boolean hasNetworkPermission(@NonNull final PackageInfo app) {
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700243 return hasPermission(app, CHANGE_NETWORK_STATE);
244 }
245
paulhu86e23eb2019-11-05 18:05:05 +0800246 @VisibleForTesting
247 boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) {
paulhub6733802018-08-20 11:01:21 +0800248 // TODO : remove this check in the future(b/31479477). All apps should just
249 // request the appropriate permission for their use case since android Q.
paulhu3b0f5ea2018-11-01 10:38:11 +0800250 if (app.applicationInfo != null) {
251 // Backward compatibility for b/114245686, on devices that launched before Q daemons
252 // and apps running as the system UID are exempted from this check.
253 if (app.applicationInfo.uid == SYSTEM_UID && getDeviceFirstSdkInt() < VERSION_Q) {
254 return true;
255 }
256
257 if (app.applicationInfo.targetSdkVersion < VERSION_Q
258 && isVendorApp(app.applicationInfo)) {
259 return true;
260 }
paulhub6733802018-08-20 11:01:21 +0800261 }
paulhu59148b72019-08-12 16:25:11 +0800262
263 return hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK)
paulhu86e23eb2019-11-05 18:05:05 +0800264 || hasPermission(app, NETWORK_STACK)
Hugo Benichi514da602016-07-19 15:59:27 +0900265 || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700266 }
267
paulhu86e23eb2019-11-05 18:05:05 +0800268 /** Returns whether the given uid has using background network permission. */
269 public synchronized boolean hasUseBackgroundNetworksPermission(final int uid) {
270 // Apps with any of the CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_INTERNAL or
271 // CONNECTIVITY_USE_RESTRICTED_NETWORKS permission has the permission to use background
272 // networks. mApps contains the result of checks for both hasNetworkPermission and
273 // hasRestrictedNetworkPermission. If uid is in the mApps list that means uid has one of
274 // permissions at least.
275 return mApps.containsKey(uid);
Chalard Jean26aa91a2018-03-20 19:13:57 +0900276 }
277
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000278 private int[] toIntArray(Collection<Integer> list) {
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700279 int[] array = new int[list.size()];
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000280 int i = 0;
281 for (Integer item : list) {
282 array[i++] = item;
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700283 }
284 return array;
285 }
286
287 private void update(Set<Integer> users, Map<Integer, Boolean> apps, boolean add) {
Hugo Benichi514da602016-07-19 15:59:27 +0900288 List<Integer> network = new ArrayList<>();
289 List<Integer> system = new ArrayList<>();
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700290 for (Entry<Integer, Boolean> app : apps.entrySet()) {
291 List<Integer> list = app.getValue() ? system : network;
292 for (int user : users) {
293 list.add(UserHandle.getUid(user, app.getKey()));
294 }
295 }
296 try {
297 if (add) {
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000298 mNetd.networkSetPermissionForUser(INetd.PERMISSION_NETWORK, toIntArray(network));
299 mNetd.networkSetPermissionForUser(INetd.PERMISSION_SYSTEM, toIntArray(system));
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700300 } else {
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000301 mNetd.networkClearPermissionForUser(toIntArray(network));
302 mNetd.networkClearPermissionForUser(toIntArray(system));
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700303 }
304 } catch (RemoteException e) {
305 loge("Exception when updating permissions: " + e);
306 }
307 }
308
junyulai2454b692018-11-01 17:16:31 +0800309 /**
310 * Called when a user is added. See {link #ACTION_USER_ADDED}.
311 *
312 * @param user The integer userHandle of the added user. See {@link #EXTRA_USER_HANDLE}.
313 *
314 * @hide
315 */
316 public synchronized void onUserAdded(int user) {
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700317 if (user < 0) {
318 loge("Invalid user in onUserAdded: " + user);
319 return;
320 }
321 mUsers.add(user);
322
Hugo Benichi514da602016-07-19 15:59:27 +0900323 Set<Integer> users = new HashSet<>();
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700324 users.add(user);
325 update(users, mApps, true);
326 }
327
junyulai2454b692018-11-01 17:16:31 +0800328 /**
329 * Called when an user is removed. See {link #ACTION_USER_REMOVED}.
330 *
331 * @param user The integer userHandle of the removed user. See {@link #EXTRA_USER_HANDLE}.
332 *
333 * @hide
334 */
335 public synchronized void onUserRemoved(int user) {
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700336 if (user < 0) {
337 loge("Invalid user in onUserRemoved: " + user);
338 return;
339 }
340 mUsers.remove(user);
341
Hugo Benichi514da602016-07-19 15:59:27 +0900342 Set<Integer> users = new HashSet<>();
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700343 users.add(user);
344 update(users, mApps, false);
345 }
346
junyulai2454b692018-11-01 17:16:31 +0800347 @VisibleForTesting
348 protected Boolean highestPermissionForUid(Boolean currentPermission, String name) {
zhangshuxiaob48db5b2016-02-03 21:28:25 +0800349 if (currentPermission == SYSTEM) {
350 return currentPermission;
351 }
352 try {
353 final PackageInfo app = mPackageManager.getPackageInfo(name, GET_PERMISSIONS);
354 final boolean isNetwork = hasNetworkPermission(app);
Hugo Benichi524b2e42016-07-26 13:08:14 +0900355 final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
356 if (isNetwork || hasRestrictedPermission) {
357 currentPermission = hasRestrictedPermission;
zhangshuxiaob48db5b2016-02-03 21:28:25 +0800358 }
359 } catch (NameNotFoundException e) {
360 // App not found.
361 loge("NameNotFoundException " + name);
362 }
363 return currentPermission;
364 }
365
junyulai2454b692018-11-01 17:16:31 +0800366 /**
367 * Called when a package is added. See {link #ACTION_PACKAGE_ADDED}.
368 *
369 * @param packageName The name of the new package.
370 * @param uid The uid of the new package.
371 *
372 * @hide
373 */
374 public synchronized void onPackageAdded(String packageName, int uid) {
zhangshuxiaob48db5b2016-02-03 21:28:25 +0800375 // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
376 // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
junyulai2454b692018-11-01 17:16:31 +0800377 final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName);
378 if (permission != mApps.get(uid)) {
379 mApps.put(uid, permission);
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700380
Hugo Benichi524b2e42016-07-26 13:08:14 +0900381 Map<Integer, Boolean> apps = new HashMap<>();
junyulai2454b692018-11-01 17:16:31 +0800382 apps.put(uid, permission);
zhangshuxiaob48db5b2016-02-03 21:28:25 +0800383 update(mUsers, apps, true);
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700384 }
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000385
386 // If the newly-installed package falls within some VPN's uid range, update Netd with it.
387 // This needs to happen after the mApps update above, since removeBypassingUids() depends
388 // on mApps to check if the package can bypass VPN.
389 for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
390 if (UidRange.containsUid(vpn.getValue(), uid)) {
391 final Set<Integer> changedUids = new HashSet<>();
392 changedUids.add(uid);
393 removeBypassingUids(changedUids, /* vpnAppUid */ -1);
394 updateVpnUids(vpn.getKey(), changedUids, true);
395 }
396 }
397 mAllApps.add(UserHandle.getAppId(uid));
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700398 }
399
junyulai2454b692018-11-01 17:16:31 +0800400 /**
401 * Called when a package is removed. See {link #ACTION_PACKAGE_REMOVED}.
402 *
403 * @param uid containing the integer uid previously assigned to the package.
404 *
405 * @hide
406 */
407 public synchronized void onPackageRemoved(int uid) {
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000408 // If the newly-removed package falls within some VPN's uid range, update Netd with it.
409 // This needs to happen before the mApps update below, since removeBypassingUids() depends
410 // on mApps to check if the package can bypass VPN.
411 for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
412 if (UidRange.containsUid(vpn.getValue(), uid)) {
413 final Set<Integer> changedUids = new HashSet<>();
414 changedUids.add(uid);
415 removeBypassingUids(changedUids, /* vpnAppUid */ -1);
416 updateVpnUids(vpn.getKey(), changedUids, false);
417 }
418 }
419 // If the package has been removed from all users on the device, clear it form mAllApps.
420 if (mPackageManager.getNameForUid(uid) == null) {
421 mAllApps.remove(UserHandle.getAppId(uid));
422 }
Remi NGUYEN VAN3897df22019-04-12 09:05:40 +0000423
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000424 Map<Integer, Boolean> apps = new HashMap<>();
zhangshuxiaob48db5b2016-02-03 21:28:25 +0800425 Boolean permission = null;
junyulai2454b692018-11-01 17:16:31 +0800426 String[] packages = mPackageManager.getPackagesForUid(uid);
zhangshuxiaob48db5b2016-02-03 21:28:25 +0800427 if (packages != null && packages.length > 0) {
428 for (String name : packages) {
429 permission = highestPermissionForUid(permission, name);
430 if (permission == SYSTEM) {
431 // An app with this UID still has the SYSTEM permission.
432 // Therefore, this UID must already have the SYSTEM permission.
433 // Nothing to do.
434 return;
435 }
436 }
437 }
junyulai2454b692018-11-01 17:16:31 +0800438 if (permission == mApps.get(uid)) {
zhangshuxiaob48db5b2016-02-03 21:28:25 +0800439 // The permissions of this UID have not changed. Nothing to do.
440 return;
441 } else if (permission != null) {
junyulai2454b692018-11-01 17:16:31 +0800442 mApps.put(uid, permission);
443 apps.put(uid, permission);
zhangshuxiaob48db5b2016-02-03 21:28:25 +0800444 update(mUsers, apps, true);
445 } else {
junyulai2454b692018-11-01 17:16:31 +0800446 mApps.remove(uid);
447 apps.put(uid, NETWORK); // doesn't matter which permission we pick here
zhangshuxiaob48db5b2016-02-03 21:28:25 +0800448 update(mUsers, apps, false);
449 }
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700450 }
451
Chenbo Fengdc179822019-03-08 11:55:12 -0800452 private static int getNetdPermissionMask(String[] requestedPermissions,
453 int[] requestedPermissionsFlags) {
Chenbo Fenge16cd662019-01-07 16:14:26 -0800454 int permissions = 0;
Chenbo Fengdc179822019-03-08 11:55:12 -0800455 if (requestedPermissions == null || requestedPermissionsFlags == null) return permissions;
456 for (int i = 0; i < requestedPermissions.length; i++) {
457 if (requestedPermissions[i].equals(INTERNET)
458 && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
Chenbo Feng14981f32019-02-21 14:24:24 -0800459 permissions |= INetd.PERMISSION_INTERNET;
460 }
Chenbo Fengdc179822019-03-08 11:55:12 -0800461 if (requestedPermissions[i].equals(UPDATE_DEVICE_STATS)
462 && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
Chenbo Feng14981f32019-02-21 14:24:24 -0800463 permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS;
464 }
Chenbo Fenge16cd662019-01-07 16:14:26 -0800465 }
466 return permissions;
467 }
468
469 private PackageInfo getPackageInfo(String packageName) {
470 try {
471 PackageInfo app = mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS
472 | MATCH_ANY_USER);
473 return app;
474 } catch (NameNotFoundException e) {
Chenbo Fenge16cd662019-01-07 16:14:26 -0800475 return null;
476 }
477 }
478
479 /**
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000480 * Called when a new set of UID ranges are added to an active VPN network
481 *
482 * @param iface The active VPN network's interface name
483 * @param rangesToAdd The new UID ranges to be added to the network
484 * @param vpnAppUid The uid of the VPN app
485 */
486 public synchronized void onVpnUidRangesAdded(@NonNull String iface, Set<UidRange> rangesToAdd,
487 int vpnAppUid) {
488 // Calculate the list of new app uids under the VPN due to the new UID ranges and update
489 // Netd about them. Because mAllApps only contains appIds instead of uids, the result might
490 // be an overestimation if an app is not installed on the user on which the VPN is running,
491 // but that's safe.
492 final Set<Integer> changedUids = intersectUids(rangesToAdd, mAllApps);
493 removeBypassingUids(changedUids, vpnAppUid);
494 updateVpnUids(iface, changedUids, true);
495 if (mVpnUidRanges.containsKey(iface)) {
496 mVpnUidRanges.get(iface).addAll(rangesToAdd);
497 } else {
498 mVpnUidRanges.put(iface, new HashSet<UidRange>(rangesToAdd));
499 }
500 }
501
502 /**
503 * Called when a set of UID ranges are removed from an active VPN network
504 *
505 * @param iface The VPN network's interface name
506 * @param rangesToRemove Existing UID ranges to be removed from the VPN network
507 * @param vpnAppUid The uid of the VPN app
508 */
509 public synchronized void onVpnUidRangesRemoved(@NonNull String iface,
510 Set<UidRange> rangesToRemove, int vpnAppUid) {
511 // Calculate the list of app uids that are no longer under the VPN due to the removed UID
512 // ranges and update Netd about them.
513 final Set<Integer> changedUids = intersectUids(rangesToRemove, mAllApps);
514 removeBypassingUids(changedUids, vpnAppUid);
515 updateVpnUids(iface, changedUids, false);
516 Set<UidRange> existingRanges = mVpnUidRanges.getOrDefault(iface, null);
517 if (existingRanges == null) {
518 loge("Attempt to remove unknown vpn uid Range iface = " + iface);
519 return;
520 }
521 existingRanges.removeAll(rangesToRemove);
522 if (existingRanges.size() == 0) {
523 mVpnUidRanges.remove(iface);
524 }
525 }
526
527 /**
528 * Compute the intersection of a set of UidRanges and appIds. Returns a set of uids
529 * that satisfies:
530 * 1. falls into one of the UidRange
531 * 2. matches one of the appIds
532 */
533 private Set<Integer> intersectUids(Set<UidRange> ranges, Set<Integer> appIds) {
534 Set<Integer> result = new HashSet<>();
535 for (UidRange range : ranges) {
536 for (int userId = range.getStartUser(); userId <= range.getEndUser(); userId++) {
537 for (int appId : appIds) {
538 final int uid = UserHandle.getUid(userId, appId);
539 if (range.contains(uid)) {
540 result.add(uid);
541 }
542 }
543 }
544 }
545 return result;
546 }
547
548 /**
549 * Remove all apps which can elect to bypass the VPN from the list of uids
550 *
551 * An app can elect to bypass the VPN if it hold SYSTEM permission, or if its the active VPN
552 * app itself.
553 *
554 * @param uids The list of uids to operate on
555 * @param vpnAppUid The uid of the VPN app
556 */
557 private void removeBypassingUids(Set<Integer> uids, int vpnAppUid) {
558 uids.remove(vpnAppUid);
559 uids.removeIf(uid -> mApps.getOrDefault(uid, NETWORK) == SYSTEM);
560 }
561
562 /**
563 * Update netd about the list of uids that are under an active VPN connection which they cannot
564 * bypass.
565 *
566 * This is to instruct netd to set up appropriate filtering rules for these uids, such that they
567 * can only receive ingress packets from the VPN's tunnel interface (and loopback).
568 *
569 * @param iface the interface name of the active VPN connection
570 * @param add {@code true} if the uids are to be added to the interface, {@code false} if they
571 * are to be removed from the interface.
572 */
573 private void updateVpnUids(String iface, Set<Integer> uids, boolean add) {
574 if (uids.size() == 0) {
575 return;
576 }
577 try {
578 if (add) {
579 mNetd.firewallAddUidInterfaceRules(iface, toIntArray(uids));
580 } else {
581 mNetd.firewallRemoveUidInterfaceRules(toIntArray(uids));
582 }
583 } catch (ServiceSpecificException e) {
584 // Silently ignore exception when device does not support eBPF, otherwise just log
585 // the exception and do not crash
586 if (e.errorCode != OsConstants.EOPNOTSUPP) {
587 loge("Exception when updating permissions: ", e);
588 }
589 } catch (RemoteException e) {
590 loge("Exception when updating permissions: ", e);
591 }
592 }
593
594 /**
Chenbo Fenge16cd662019-01-07 16:14:26 -0800595 * Called by PackageListObserver when a package is installed/uninstalled. Send the updated
596 * permission information to netd.
597 *
598 * @param uid the app uid of the package installed
599 * @param permissions the permissions the app requested and netd cares about.
600 *
601 * @hide
602 */
Chenbo Feng436fe582019-02-25 22:55:58 -0800603 @VisibleForTesting
604 void sendPackagePermissionsForUid(int uid, int permissions) {
Chenbo Fenge16cd662019-01-07 16:14:26 -0800605 SparseIntArray netdPermissionsAppIds = new SparseIntArray();
606 netdPermissionsAppIds.put(uid, permissions);
607 sendPackagePermissionsToNetd(netdPermissionsAppIds);
608 }
609
610 /**
611 * Called by packageManagerService to send IPC to netd. Grant or revoke the INTERNET
612 * and/or UPDATE_DEVICE_STATS permission of the uids in array.
613 *
614 * @param netdPermissionsAppIds integer pairs of uids and the permission granted to it. If the
615 * permission is 0, revoke all permissions of that uid.
616 *
617 * @hide
618 */
Chenbo Feng436fe582019-02-25 22:55:58 -0800619 @VisibleForTesting
620 void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
paulhu8a7d2b02019-04-04 00:07:40 +0800621 if (mNetd == null) {
622 Log.e(TAG, "Failed to get the netd service");
623 return;
624 }
Chenbo Fenge16cd662019-01-07 16:14:26 -0800625 ArrayList<Integer> allPermissionAppIds = new ArrayList<>();
626 ArrayList<Integer> internetPermissionAppIds = new ArrayList<>();
627 ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
Chenbo Fenga6817cd2019-03-25 18:13:34 -0700628 ArrayList<Integer> noPermissionAppIds = new ArrayList<>();
Chenbo Fenge16cd662019-01-07 16:14:26 -0800629 ArrayList<Integer> uninstalledAppIds = new ArrayList<>();
630 for (int i = 0; i < netdPermissionsAppIds.size(); i++) {
631 int permissions = netdPermissionsAppIds.valueAt(i);
632 switch(permissions) {
633 case (INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS):
634 allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
635 break;
636 case INetd.PERMISSION_INTERNET:
637 internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
638 break;
639 case INetd.PERMISSION_UPDATE_DEVICE_STATS:
640 updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
641 break;
Chenbo Feng05887f92019-04-19 16:05:03 -0700642 case INetd.PERMISSION_NONE:
Chenbo Fenga6817cd2019-03-25 18:13:34 -0700643 noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
Chenbo Fenge16cd662019-01-07 16:14:26 -0800644 break;
Chenbo Fenga6817cd2019-03-25 18:13:34 -0700645 case INetd.PERMISSION_UNINSTALLED:
646 uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
Chenbo Fenge16cd662019-01-07 16:14:26 -0800647 default:
648 Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
649 + netdPermissionsAppIds.keyAt(i));
650 }
651 }
652 try {
653 // TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids()
654 if (allPermissionAppIds.size() != 0) {
Chenbo Feng436fe582019-02-25 22:55:58 -0800655 mNetd.trafficSetNetPermForUids(
Chenbo Fenge16cd662019-01-07 16:14:26 -0800656 INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
657 ArrayUtils.convertToIntArray(allPermissionAppIds));
658 }
659 if (internetPermissionAppIds.size() != 0) {
Chenbo Feng436fe582019-02-25 22:55:58 -0800660 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
Chenbo Fenge16cd662019-01-07 16:14:26 -0800661 ArrayUtils.convertToIntArray(internetPermissionAppIds));
662 }
663 if (updateStatsPermissionAppIds.size() != 0) {
Chenbo Feng436fe582019-02-25 22:55:58 -0800664 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
Chenbo Fenge16cd662019-01-07 16:14:26 -0800665 ArrayUtils.convertToIntArray(updateStatsPermissionAppIds));
666 }
Chenbo Fenga6817cd2019-03-25 18:13:34 -0700667 if (noPermissionAppIds.size() != 0) {
Chenbo Feng05887f92019-04-19 16:05:03 -0700668 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE,
Chenbo Fenga6817cd2019-03-25 18:13:34 -0700669 ArrayUtils.convertToIntArray(noPermissionAppIds));
670 }
671 if (uninstalledAppIds.size() != 0) {
672 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UNINSTALLED,
Chenbo Fenge16cd662019-01-07 16:14:26 -0800673 ArrayUtils.convertToIntArray(uninstalledAppIds));
674 }
675 } catch (RemoteException e) {
676 Log.e(TAG, "Pass appId list of special permission failed." + e);
677 }
678 }
679
Lorenzo Colitti4c9f9542019-04-12 10:48:06 +0000680 /** Should only be used by unit tests */
681 @VisibleForTesting
682 public Set<UidRange> getVpnUidRanges(String iface) {
683 return mVpnUidRanges.get(iface);
684 }
685
686 /** Dump info to dumpsys */
687 public void dump(IndentingPrintWriter pw) {
688 pw.println("Interface filtering rules:");
689 pw.increaseIndent();
690 for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
691 pw.println("Interface: " + vpn.getKey());
692 pw.println("UIDs: " + vpn.getValue().toString());
693 pw.println();
694 }
695 pw.decreaseIndent();
696 }
697
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700698 private static void log(String s) {
699 if (DBG) {
700 Log.d(TAG, s);
701 }
702 }
703
704 private static void loge(String s) {
705 Log.e(TAG, s);
706 }
Chalard Jean26aa91a2018-03-20 19:13:57 +0900707
708 private static void loge(String s, Throwable e) {
709 Log.e(TAG, s, e);
710 }
Sreeram Ramachandrane4a05af2014-09-24 09:16:19 -0700711}