blob: 0ff88102ac8538c6b769b2fdef50d5887b871e62 [file] [log] [blame]
Wayne Ma0ea3bdc2022-01-12 01:12:11 +08001/*
2 * Copyright (C) 2022 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;
18
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +000019import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
20import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
21import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1;
22import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2;
23import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3;
24import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
25import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
26import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
Motomu Utsumi40230be2022-07-05 03:27:35 +000027import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
28import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
Motomu Utsumi18b287d2022-06-19 10:45:30 +000029import static android.system.OsConstants.EINVAL;
Motomu Utsumi5f52f4f2022-06-30 03:31:09 +000030import static android.system.OsConstants.ENODEV;
Motomu Utsumi60ed3be2022-06-24 10:38:57 +000031import static android.system.OsConstants.ENOENT;
Ken Chene6d511f2022-01-25 11:10:42 +080032import static android.system.OsConstants.EOPNOTSUPP;
33
Wayne Ma2fde98c2022-01-17 18:04:05 +080034import android.net.INetd;
35import android.os.RemoteException;
Wayne Ma0ea3bdc2022-01-12 01:12:11 +080036import android.os.ServiceSpecificException;
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +000037import android.system.ErrnoException;
Wayne Ma0ea3bdc2022-01-12 01:12:11 +080038import android.system.Os;
39import android.util.Log;
40
Motomu Utsumi5a68a212022-06-24 10:14:31 +000041import com.android.internal.annotations.GuardedBy;
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +000042import com.android.internal.annotations.VisibleForTesting;
Ken Chenf5f51332022-01-28 10:08:16 +080043import com.android.modules.utils.build.SdkLevel;
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +000044import com.android.net.module.util.BpfMap;
45import com.android.net.module.util.Struct.U32;
Ken Chenf5f51332022-01-28 10:08:16 +080046
Ken Chene6d511f2022-01-25 11:10:42 +080047import java.io.FileDescriptor;
48import java.io.IOException;
Motomu Utsumi9be2ea02022-07-05 06:14:59 +000049import java.util.Arrays;
50import java.util.HashSet;
51import java.util.Set;
52import java.util.stream.Collectors;
Ken Chene6d511f2022-01-25 11:10:42 +080053
Wayne Ma0ea3bdc2022-01-12 01:12:11 +080054/**
55 * BpfNetMaps is responsible for providing traffic controller relevant functionality.
56 *
57 * {@hide}
58 */
59public class BpfNetMaps {
Motomu Utsumi305975f2022-06-27 09:24:32 +000060 private static final boolean PRE_T = !SdkLevel.isAtLeastT();
61 static {
62 if (!PRE_T) {
63 System.loadLibrary("service-connectivity");
64 }
65 }
66
Wayne Ma0ea3bdc2022-01-12 01:12:11 +080067 private static final String TAG = "BpfNetMaps";
Wayne Ma2fde98c2022-01-17 18:04:05 +080068 private final INetd mNetd;
Motomu Utsumi5f52f4f2022-06-30 03:31:09 +000069 private final Dependencies mDeps;
Ken Chenf5f51332022-01-28 10:08:16 +080070 // Use legacy netd for releases before T.
Ken Chenf5f51332022-01-28 10:08:16 +080071 private static boolean sInitialized = false;
Wayne Ma0ea3bdc2022-01-12 01:12:11 +080072
Motomu Utsumi18b287d2022-06-19 10:45:30 +000073 // Lock for sConfigurationMap entry for UID_RULES_CONFIGURATION_KEY.
74 // This entry is not accessed by others.
75 // BpfNetMaps acquires this lock while sequence of read, modify, and write.
76 private static final Object sUidRulesConfigBpfMapLock = new Object();
77
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +000078 private static final String CONFIGURATION_MAP_PATH =
79 "/sys/fs/bpf/netd_shared/map_netd_configuration_map";
Motomu Utsumi5a68a212022-06-24 10:14:31 +000080 private static final String UID_OWNER_MAP_PATH =
81 "/sys/fs/bpf/netd_shared/map_netd_uid_owner_map";
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +000082 private static final U32 UID_RULES_CONFIGURATION_KEY = new U32(0);
83 private static BpfMap<U32, U32> sConfigurationMap = null;
Motomu Utsumi5a68a212022-06-24 10:14:31 +000084 // BpfMap for UID_OWNER_MAP_PATH. This map is not accessed by others.
85 private static BpfMap<U32, UidOwnerValue> sUidOwnerMap = null;
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +000086
87 // LINT.IfChange(match_type)
Motomu Utsumi60ed3be2022-06-24 10:38:57 +000088 @VisibleForTesting public static final long NO_MATCH = 0;
89 @VisibleForTesting public static final long HAPPY_BOX_MATCH = (1 << 0);
90 @VisibleForTesting public static final long PENALTY_BOX_MATCH = (1 << 1);
91 @VisibleForTesting public static final long DOZABLE_MATCH = (1 << 2);
92 @VisibleForTesting public static final long STANDBY_MATCH = (1 << 3);
93 @VisibleForTesting public static final long POWERSAVE_MATCH = (1 << 4);
94 @VisibleForTesting public static final long RESTRICTED_MATCH = (1 << 5);
95 @VisibleForTesting public static final long LOW_POWER_STANDBY_MATCH = (1 << 6);
96 @VisibleForTesting public static final long IIF_MATCH = (1 << 7);
97 @VisibleForTesting public static final long LOCKDOWN_VPN_MATCH = (1 << 8);
98 @VisibleForTesting public static final long OEM_DENY_1_MATCH = (1 << 9);
99 @VisibleForTesting public static final long OEM_DENY_2_MATCH = (1 << 10);
100 @VisibleForTesting public static final long OEM_DENY_3_MATCH = (1 << 11);
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000101 // LINT.ThenChange(packages/modules/Connectivity/bpf_progs/bpf_shared.h)
102
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000103 /**
Motomu Utsumi305975f2022-06-27 09:24:32 +0000104 * Set configurationMap for test.
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000105 */
106 @VisibleForTesting
Motomu Utsumi305975f2022-06-27 09:24:32 +0000107 public static void setConfigurationMapForTest(BpfMap<U32, U32> configurationMap) {
108 sConfigurationMap = configurationMap;
109 }
110
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000111 /**
112 * Set uidOwnerMap for test.
113 */
114 @VisibleForTesting
115 public static void setUidOwnerMapForTest(BpfMap<U32, UidOwnerValue> uidOwnerMap) {
116 sUidOwnerMap = uidOwnerMap;
117 }
118
Motomu Utsumi305975f2022-06-27 09:24:32 +0000119 private static BpfMap<U32, U32> getConfigurationMap() {
120 try {
121 return new BpfMap<>(
122 CONFIGURATION_MAP_PATH, BpfMap.BPF_F_RDWR, U32.class, U32.class);
123 } catch (ErrnoException e) {
124 throw new IllegalStateException("Cannot open netd configuration map", e);
125 }
126 }
127
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000128 private static BpfMap<U32, UidOwnerValue> getUidOwnerMap() {
129 try {
130 return new BpfMap<>(
131 UID_OWNER_MAP_PATH, BpfMap.BPF_F_RDWR, U32.class, UidOwnerValue.class);
132 } catch (ErrnoException e) {
133 throw new IllegalStateException("Cannot open uid owner map", e);
134 }
135 }
136
Motomu Utsumi305975f2022-06-27 09:24:32 +0000137 private static void setBpfMaps() {
138 if (sConfigurationMap == null) {
139 sConfigurationMap = getConfigurationMap();
140 }
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000141 if (sUidOwnerMap == null) {
142 sUidOwnerMap = getUidOwnerMap();
143 }
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000144 }
145
Ken Chenf5f51332022-01-28 10:08:16 +0800146 /**
147 * Initializes the class if it is not already initialized. This method will open maps but not
148 * cause any other effects. This method may be called multiple times on any thread.
149 */
150 private static synchronized void ensureInitialized() {
151 if (sInitialized) return;
Motomu Utsumi305975f2022-06-27 09:24:32 +0000152 setBpfMaps();
153 native_init();
Ken Chenf5f51332022-01-28 10:08:16 +0800154 sInitialized = true;
Wayne Ma2fde98c2022-01-17 18:04:05 +0800155 }
156
Motomu Utsumi5f52f4f2022-06-30 03:31:09 +0000157 /**
158 * Dependencies of BpfNetMaps, for injection in tests.
159 */
160 @VisibleForTesting
161 public static class Dependencies {
162 /**
163 * Get interface index.
164 */
165 public int getIfIndex(final String ifName) {
166 return Os.if_nametoindex(ifName);
167 }
168 }
169
markchien49e944c2022-03-01 15:22:20 +0800170 /** Constructor used after T that doesn't need to use netd anymore. */
171 public BpfNetMaps() {
172 this(null);
173
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000174 if (PRE_T) throw new IllegalArgumentException("BpfNetMaps need to use netd before T");
markchien49e944c2022-03-01 15:22:20 +0800175 }
176
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000177 public BpfNetMaps(final INetd netd) {
Motomu Utsumi5f52f4f2022-06-30 03:31:09 +0000178 this(netd, new Dependencies());
179 }
180
181 @VisibleForTesting
182 public BpfNetMaps(final INetd netd, final Dependencies deps) {
Motomu Utsumi305975f2022-06-27 09:24:32 +0000183 if (!PRE_T) {
184 ensureInitialized();
185 }
Wayne Ma2fde98c2022-01-17 18:04:05 +0800186 mNetd = netd;
Motomu Utsumi5f52f4f2022-06-30 03:31:09 +0000187 mDeps = deps;
Wayne Ma790c83e2022-01-13 10:35:05 +0800188 }
189
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000190 /**
191 * Get corresponding match from firewall chain.
192 */
193 @VisibleForTesting
194 public long getMatchByFirewallChain(final int chain) {
Motomu Utsumi40230be2022-07-05 03:27:35 +0000195 switch (chain) {
196 case FIREWALL_CHAIN_DOZABLE:
197 return DOZABLE_MATCH;
198 case FIREWALL_CHAIN_STANDBY:
199 return STANDBY_MATCH;
200 case FIREWALL_CHAIN_POWERSAVE:
201 return POWERSAVE_MATCH;
202 case FIREWALL_CHAIN_RESTRICTED:
203 return RESTRICTED_MATCH;
204 case FIREWALL_CHAIN_LOW_POWER_STANDBY:
205 return LOW_POWER_STANDBY_MATCH;
206 case FIREWALL_CHAIN_OEM_DENY_1:
207 return OEM_DENY_1_MATCH;
208 case FIREWALL_CHAIN_OEM_DENY_2:
209 return OEM_DENY_2_MATCH;
210 case FIREWALL_CHAIN_OEM_DENY_3:
211 return OEM_DENY_3_MATCH;
212 default:
213 throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain);
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000214 }
Motomu Utsumi40230be2022-07-05 03:27:35 +0000215 }
216
217 /**
218 * Get if the chain is allow list or not.
219 *
220 * ALLOWLIST means the firewall denies all by default, uids must be explicitly allowed
221 * DENYLIST means the firewall allows all by default, uids must be explicitly denyed
222 */
223 @VisibleForTesting
224 public boolean isFirewallAllowList(final int chain) {
225 switch (chain) {
226 case FIREWALL_CHAIN_DOZABLE:
227 case FIREWALL_CHAIN_POWERSAVE:
228 case FIREWALL_CHAIN_RESTRICTED:
229 case FIREWALL_CHAIN_LOW_POWER_STANDBY:
230 return true;
231 case FIREWALL_CHAIN_STANDBY:
232 case FIREWALL_CHAIN_OEM_DENY_1:
233 case FIREWALL_CHAIN_OEM_DENY_2:
234 case FIREWALL_CHAIN_OEM_DENY_3:
235 return false;
236 default:
237 throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain);
238 }
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000239 }
240
Ken Chenf5f51332022-01-28 10:08:16 +0800241 private void maybeThrow(final int err, final String msg) {
242 if (err != 0) {
243 throw new ServiceSpecificException(err, msg + ": " + Os.strerror(err));
244 }
245 }
246
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000247 private void throwIfPreT(final String msg) {
248 if (PRE_T) {
Motomu Utsumi18b287d2022-06-19 10:45:30 +0000249 throw new UnsupportedOperationException(msg);
250 }
251 }
252
Motomu Utsumi60ed3be2022-06-24 10:38:57 +0000253 private void removeRule(final int uid, final long match, final String caller) {
254 try {
255 synchronized (sUidOwnerMap) {
256 final UidOwnerValue oldMatch = sUidOwnerMap.getValue(new U32(uid));
257
258 if (oldMatch == null) {
259 throw new ServiceSpecificException(ENOENT,
260 "sUidOwnerMap does not have entry for uid: " + uid);
261 }
262
263 final UidOwnerValue newMatch = new UidOwnerValue(
264 (match == IIF_MATCH) ? 0 : oldMatch.iif,
265 oldMatch.rule & ~match
266 );
267
268 if (newMatch.rule == 0) {
269 sUidOwnerMap.deleteEntry(new U32(uid));
270 } else {
271 sUidOwnerMap.updateEntry(new U32(uid), newMatch);
272 }
273 }
274 } catch (ErrnoException e) {
275 throw new ServiceSpecificException(e.errno,
276 caller + " failed to remove rule: " + Os.strerror(e.errno));
277 }
278 }
279
Motomu Utsumi389278e2022-06-28 07:05:05 +0000280 private void addRule(final int uid, final long match, final long iif, final String caller) {
281 if (match != IIF_MATCH && iif != 0) {
282 throw new ServiceSpecificException(EINVAL,
283 "Non-interface match must have zero interface index");
284 }
285
286 try {
287 synchronized (sUidOwnerMap) {
288 final UidOwnerValue oldMatch = sUidOwnerMap.getValue(new U32(uid));
289
290 final UidOwnerValue newMatch;
291 if (oldMatch != null) {
292 newMatch = new UidOwnerValue(
293 (match == IIF_MATCH) ? iif : oldMatch.iif,
294 oldMatch.rule | match
295 );
296 } else {
297 newMatch = new UidOwnerValue(
298 iif,
299 match
300 );
301 }
302 sUidOwnerMap.updateEntry(new U32(uid), newMatch);
303 }
304 } catch (ErrnoException e) {
305 throw new ServiceSpecificException(e.errno,
306 caller + " failed to add rule: " + Os.strerror(e.errno));
307 }
308 }
309
310 private void addRule(final int uid, final long match, final String caller) {
311 addRule(uid, match, 0 /* iif */, caller);
312 }
313
Ken Chenf5f51332022-01-28 10:08:16 +0800314 /**
315 * Add naughty app bandwidth rule for specific app
316 *
317 * @param uid uid of target app
Ken Chenf5f51332022-01-28 10:08:16 +0800318 * @throws ServiceSpecificException in case of failure, with an error code indicating the
319 * cause of the failure.
320 */
Lorenzo Colitti82244fd2022-03-04 23:15:00 +0900321 public void addNaughtyApp(final int uid) {
Motomu Utsumi389278e2022-06-28 07:05:05 +0000322 throwIfPreT("addNaughtyApp is not available on pre-T devices");
323 addRule(uid, PENALTY_BOX_MATCH, "addNaughtyApp");
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800324 }
325
Ken Chenf5f51332022-01-28 10:08:16 +0800326 /**
327 * Remove naughty app bandwidth rule for specific app
328 *
329 * @param uid uid of target app
Ken Chenf5f51332022-01-28 10:08:16 +0800330 * @throws ServiceSpecificException in case of failure, with an error code indicating the
331 * cause of the failure.
332 */
Lorenzo Colitti82244fd2022-03-04 23:15:00 +0900333 public void removeNaughtyApp(final int uid) {
Motomu Utsumi60ed3be2022-06-24 10:38:57 +0000334 throwIfPreT("removeNaughtyApp is not available on pre-T devices");
335 removeRule(uid, PENALTY_BOX_MATCH, "removeNaughtyApp");
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800336 }
337
Ken Chenf5f51332022-01-28 10:08:16 +0800338 /**
339 * Add nice app bandwidth rule for specific app
340 *
341 * @param uid uid of target app
Ken Chenf5f51332022-01-28 10:08:16 +0800342 * @throws ServiceSpecificException in case of failure, with an error code indicating the
343 * cause of the failure.
344 */
Lorenzo Colitti82244fd2022-03-04 23:15:00 +0900345 public void addNiceApp(final int uid) {
Motomu Utsumi55630d02022-06-29 07:46:52 +0000346 throwIfPreT("addNiceApp is not available on pre-T devices");
347 addRule(uid, HAPPY_BOX_MATCH, "addNiceApp");
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800348 }
349
Ken Chenf5f51332022-01-28 10:08:16 +0800350 /**
351 * Remove nice app bandwidth rule for specific app
352 *
353 * @param uid uid of target app
Ken Chenf5f51332022-01-28 10:08:16 +0800354 * @throws ServiceSpecificException in case of failure, with an error code indicating the
355 * cause of the failure.
356 */
Lorenzo Colitti82244fd2022-03-04 23:15:00 +0900357 public void removeNiceApp(final int uid) {
Motomu Utsumi7392eb42022-06-29 03:53:03 +0000358 throwIfPreT("removeNiceApp is not available on pre-T devices");
359 removeRule(uid, HAPPY_BOX_MATCH, "removeNiceApp");
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800360 }
361
Ken Chenf5f51332022-01-28 10:08:16 +0800362 /**
363 * Set target firewall child chain
364 *
365 * @param childChain target chain to enable
366 * @param enable whether to enable or disable child chain.
Motomu Utsumi18b287d2022-06-19 10:45:30 +0000367 * @throws UnsupportedOperationException if called on pre-T devices.
Ken Chenf5f51332022-01-28 10:08:16 +0800368 * @throws ServiceSpecificException in case of failure, with an error code indicating the
369 * cause of the failure.
370 */
Lorenzo Colitti82244fd2022-03-04 23:15:00 +0900371 public void setChildChain(final int childChain, final boolean enable) {
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000372 throwIfPreT("setChildChain is not available on pre-T devices");
Motomu Utsumi18b287d2022-06-19 10:45:30 +0000373
374 final long match = getMatchByFirewallChain(childChain);
375 try {
376 synchronized (sUidRulesConfigBpfMapLock) {
377 final U32 config = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY);
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000378 final long newConfig = enable ? (config.val | match) : (config.val & ~match);
Motomu Utsumi18b287d2022-06-19 10:45:30 +0000379 sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(newConfig));
380 }
381 } catch (ErrnoException e) {
382 throw new ServiceSpecificException(e.errno,
383 "Unable to set child chain: " + Os.strerror(e.errno));
384 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800385 }
386
387 /**
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000388 * Get the specified firewall chain's status.
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000389 *
390 * @param childChain target chain
391 * @return {@code true} if chain is enabled, {@code false} if chain is not enabled.
392 * @throws UnsupportedOperationException if called on pre-T devices.
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000393 * @throws ServiceSpecificException in case of failure, with an error code indicating the
394 * cause of the failure.
395 */
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000396 public boolean isChainEnabled(final int childChain) {
397 throwIfPreT("isChainEnabled is not available on pre-T devices");
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000398
399 final long match = getMatchByFirewallChain(childChain);
400 try {
401 final U32 config = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY);
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000402 return (config.val & match) != 0;
403 } catch (ErrnoException e) {
404 throw new ServiceSpecificException(e.errno,
405 "Unable to get firewall chain status: " + Os.strerror(e.errno));
406 }
407 }
408
409 /**
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800410 * Replaces the contents of the specified UID-based firewall chain.
Motomu Utsumi9be2ea02022-07-05 06:14:59 +0000411 * Enables the chain for specified uids and disables the chain for non-specified uids.
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800412 *
Motomu Utsumi9be2ea02022-07-05 06:14:59 +0000413 * @param chain Target chain.
Ken Chenf5f51332022-01-28 10:08:16 +0800414 * @param uids The list of UIDs to allow/deny.
Motomu Utsumi9be2ea02022-07-05 06:14:59 +0000415 * @throws UnsupportedOperationException if called on pre-T devices.
416 * @throws IllegalArgumentException if {@code chain} is not a valid chain.
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800417 */
Motomu Utsumi9be2ea02022-07-05 06:14:59 +0000418 public void replaceUidChain(final int chain, final int[] uids) {
419 throwIfPreT("replaceUidChain is not available on pre-T devices");
420
421 final long match;
422 try {
423 match = getMatchByFirewallChain(chain);
424 } catch (ServiceSpecificException e) {
425 // Throws IllegalArgumentException to keep the behavior of
426 // ConnectivityManager#replaceFirewallChain API
427 throw new IllegalArgumentException("Invalid firewall chain: " + chain);
428 }
429 final Set<Integer> uidSet = Arrays.stream(uids).boxed().collect(Collectors.toSet());
430 final Set<Integer> uidSetToRemoveRule = new HashSet<>();
431 try {
432 synchronized (sUidOwnerMap) {
433 sUidOwnerMap.forEach((uid, config) -> {
434 // config could be null if there is a concurrent entry deletion.
435 // http://b/220084230.
436 if (config != null
437 && !uidSet.contains((int) uid.val) && (config.rule & match) != 0) {
438 uidSetToRemoveRule.add((int) uid.val);
439 }
440 });
441
442 for (final int uid : uidSetToRemoveRule) {
443 removeRule(uid, match, "replaceUidChain");
444 }
445 for (final int uid : uids) {
446 addRule(uid, match, "replaceUidChain");
447 }
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000448 }
Motomu Utsumi9be2ea02022-07-05 06:14:59 +0000449 } catch (ErrnoException | ServiceSpecificException e) {
450 Log.e(TAG, "replaceUidChain failed: " + e);
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800451 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800452 }
453
Ken Chenf5f51332022-01-28 10:08:16 +0800454 /**
455 * Set firewall rule for uid
456 *
457 * @param childChain target chain
458 * @param uid uid to allow/deny
459 * @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY
Ken Chenf5f51332022-01-28 10:08:16 +0800460 * @throws ServiceSpecificException in case of failure, with an error code indicating the
461 * cause of the failure.
462 */
Lorenzo Colitti82244fd2022-03-04 23:15:00 +0900463 public void setUidRule(final int childChain, final int uid, final int firewallRule) {
Motomu Utsumi40230be2022-07-05 03:27:35 +0000464 throwIfPreT("setUidRule is not available on pre-T devices");
465
466 final long match = getMatchByFirewallChain(childChain);
467 final boolean isAllowList = isFirewallAllowList(childChain);
468 final boolean add = (firewallRule == FIREWALL_RULE_ALLOW && isAllowList)
469 || (firewallRule == FIREWALL_RULE_DENY && !isAllowList);
470
471 if (add) {
472 addRule(uid, match, "setUidRule");
473 } else {
474 removeRule(uid, match, "setUidRule");
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000475 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800476 }
477
478 /**
479 * Add ingress interface filtering rules to a list of UIDs
480 *
481 * For a given uid, once a filtering rule is added, the kernel will only allow packets from the
482 * allowed interface and loopback to be sent to the list of UIDs.
483 *
484 * Calling this method on one or more UIDs with an existing filtering rule but a different
485 * interface name will result in the filtering rule being updated to allow the new interface
486 * instead. Otherwise calling this method will not affect existing rules set on other UIDs.
487 *
488 * @param ifName the name of the interface on which the filtering rules will allow packets to
Ken Chenf5f51332022-01-28 10:08:16 +0800489 * be received.
490 * @param uids an array of UIDs which the filtering rules will be set
491 * @throws RemoteException when netd has crashed.
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800492 * @throws ServiceSpecificException in case of failure, with an error code indicating the
Ken Chenf5f51332022-01-28 10:08:16 +0800493 * cause of the failure.
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800494 */
Ken Chenf5f51332022-01-28 10:08:16 +0800495 public void addUidInterfaceRules(final String ifName, final int[] uids) throws RemoteException {
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000496 if (PRE_T) {
Ken Chenf5f51332022-01-28 10:08:16 +0800497 mNetd.firewallAddUidInterfaceRules(ifName, uids);
Wayne Ma2fde98c2022-01-17 18:04:05 +0800498 return;
499 }
Motomu Utsumi5f52f4f2022-06-30 03:31:09 +0000500 // Null ifName is a wildcard to allow apps to receive packets on all interfaces and ifIndex
501 // is set to 0.
502 final int ifIndex;
503 if (ifName == null) {
504 ifIndex = 0;
505 } else {
506 ifIndex = mDeps.getIfIndex(ifName);
507 if (ifIndex == 0) {
508 throw new ServiceSpecificException(ENODEV,
509 "Failed to get index of interface " + ifName);
510 }
511 }
512 for (final int uid: uids) {
513 try {
514 addRule(uid, IIF_MATCH, ifIndex, "addUidInterfaceRules");
515 } catch (ServiceSpecificException e) {
516 Log.e(TAG, "addRule failed uid=" + uid + " ifName=" + ifName + ", " + e);
517 }
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000518 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800519 }
520
521 /**
522 * Remove ingress interface filtering rules from a list of UIDs
523 *
524 * Clear the ingress interface filtering rules from the list of UIDs which were previously set
525 * by addUidInterfaceRules(). Ignore any uid which does not have filtering rule.
526 *
527 * @param uids an array of UIDs from which the filtering rules will be removed
Ken Chenf5f51332022-01-28 10:08:16 +0800528 * @throws RemoteException when netd has crashed.
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800529 * @throws ServiceSpecificException in case of failure, with an error code indicating the
Ken Chenf5f51332022-01-28 10:08:16 +0800530 * cause of the failure.
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800531 */
Ken Chenf5f51332022-01-28 10:08:16 +0800532 public void removeUidInterfaceRules(final int[] uids) throws RemoteException {
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000533 if (PRE_T) {
Ken Chenf5f51332022-01-28 10:08:16 +0800534 mNetd.firewallRemoveUidInterfaceRules(uids);
Wayne Ma2fde98c2022-01-17 18:04:05 +0800535 return;
536 }
Motomu Utsumi599c4e52022-06-30 03:37:18 +0000537 for (final int uid: uids) {
538 try {
539 removeRule(uid, IIF_MATCH, "removeUidInterfaceRules");
540 } catch (ServiceSpecificException e) {
541 Log.e(TAG, "removeRule failed uid=" + uid + ", " + e);
542 }
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000543 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800544 }
545
Ken Chenf5f51332022-01-28 10:08:16 +0800546 /**
Motomu Utsumi8b42e6d2022-05-19 06:23:40 +0000547 * Update lockdown rule for uid
548 *
549 * @param uid target uid to add/remove the rule
550 * @param add {@code true} to add the rule, {@code false} to remove the rule.
551 * @throws ServiceSpecificException in case of failure, with an error code indicating the
552 * cause of the failure.
553 */
554 public void updateUidLockdownRule(final int uid, final boolean add) {
Motomu Utsumi697b2992022-06-30 02:25:29 +0000555 throwIfPreT("updateUidLockdownRule is not available on pre-T devices");
556 if (add) {
557 addRule(uid, LOCKDOWN_VPN_MATCH, "updateUidLockdownRule");
558 } else {
559 removeRule(uid, LOCKDOWN_VPN_MATCH, "updateUidLockdownRule");
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000560 }
Motomu Utsumi8b42e6d2022-05-19 06:23:40 +0000561 }
562
563 /**
Ken Chenf5f51332022-01-28 10:08:16 +0800564 * Request netd to change the current active network stats map.
565 *
Ken Chenf5f51332022-01-28 10:08:16 +0800566 * @throws ServiceSpecificException in case of failure, with an error code indicating the
567 * cause of the failure.
568 */
markchien49e944c2022-03-01 15:22:20 +0800569 public void swapActiveStatsMap() {
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800570 final int err = native_swapActiveStatsMap();
Ken Chenf5f51332022-01-28 10:08:16 +0800571 maybeThrow(err, "Unable to swap active stats map");
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800572 }
573
Ken Chenf5f51332022-01-28 10:08:16 +0800574 /**
575 * Assigns android.permission.INTERNET and/or android.permission.UPDATE_DEVICE_STATS to the uids
576 * specified. Or remove all permissions from the uids.
577 *
578 * @param permissions The permission to grant, it could be either PERMISSION_INTERNET and/or
579 * PERMISSION_UPDATE_DEVICE_STATS. If the permission is NO_PERMISSIONS, then
580 * revoke all permissions for the uids.
581 * @param uids uid of users to grant permission
582 * @throws RemoteException when netd has crashed.
583 */
584 public void setNetPermForUids(final int permissions, final int[] uids) throws RemoteException {
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000585 if (PRE_T) {
Ken Chenf5f51332022-01-28 10:08:16 +0800586 mNetd.trafficSetNetPermForUids(permissions, uids);
Wayne Ma2fde98c2022-01-17 18:04:05 +0800587 return;
588 }
589 native_setPermissionForUids(permissions, uids);
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800590 }
591
Ken Chene6d511f2022-01-25 11:10:42 +0800592 /**
593 * Dump BPF maps
594 *
595 * @param fd file descriptor to output
596 * @throws IOException when file descriptor is invalid.
597 * @throws ServiceSpecificException when the method is called on an unsupported device.
598 */
599 public void dump(final FileDescriptor fd, boolean verbose)
600 throws IOException, ServiceSpecificException {
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000601 if (PRE_T) {
Ken Chene6d511f2022-01-25 11:10:42 +0800602 throw new ServiceSpecificException(
603 EOPNOTSUPP, "dumpsys connectivity trafficcontroller dump not available on pre-T"
604 + " devices, use dumpsys netd trafficcontroller instead.");
605 }
606 native_dump(fd, verbose);
607 }
608
Wayne Ma790c83e2022-01-13 10:35:05 +0800609 private static native void native_init();
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000610 @GuardedBy("sUidOwnerMap")
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800611 private native int native_addNaughtyApp(int uid);
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000612 @GuardedBy("sUidOwnerMap")
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800613 private native int native_removeNaughtyApp(int uid);
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000614 @GuardedBy("sUidOwnerMap")
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800615 private native int native_addNiceApp(int uid);
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000616 @GuardedBy("sUidOwnerMap")
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800617 private native int native_removeNiceApp(int uid);
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000618 @GuardedBy("sUidOwnerMap")
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800619 private native int native_replaceUidChain(String name, boolean isAllowlist, int[] uids);
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000620 @GuardedBy("sUidOwnerMap")
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800621 private native int native_setUidRule(int childChain, int uid, int firewallRule);
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000622 @GuardedBy("sUidOwnerMap")
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800623 private native int native_addUidInterfaceRules(String ifName, int[] uids);
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000624 @GuardedBy("sUidOwnerMap")
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800625 private native int native_removeUidInterfaceRules(int[] uids);
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000626 @GuardedBy("sUidOwnerMap")
Motomu Utsumi8b42e6d2022-05-19 06:23:40 +0000627 private native int native_updateUidLockdownRule(int uid, boolean add);
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800628 private native int native_swapActiveStatsMap();
Wayne Ma2fde98c2022-01-17 18:04:05 +0800629 private native void native_setPermissionForUids(int permissions, int[] uids);
Ken Chene6d511f2022-01-25 11:10:42 +0800630 private native void native_dump(FileDescriptor fd, boolean verbose);
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800631}