blob: d7c5a0653af72421363f84b4ecd3e8b77e1d0d04 [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;
49
Wayne Ma0ea3bdc2022-01-12 01:12:11 +080050/**
51 * BpfNetMaps is responsible for providing traffic controller relevant functionality.
52 *
53 * {@hide}
54 */
55public class BpfNetMaps {
Motomu Utsumi305975f2022-06-27 09:24:32 +000056 private static final boolean PRE_T = !SdkLevel.isAtLeastT();
57 static {
58 if (!PRE_T) {
59 System.loadLibrary("service-connectivity");
60 }
61 }
62
Wayne Ma0ea3bdc2022-01-12 01:12:11 +080063 private static final String TAG = "BpfNetMaps";
Wayne Ma2fde98c2022-01-17 18:04:05 +080064 private final INetd mNetd;
Motomu Utsumi5f52f4f2022-06-30 03:31:09 +000065 private final Dependencies mDeps;
Ken Chenf5f51332022-01-28 10:08:16 +080066 // Use legacy netd for releases before T.
Ken Chenf5f51332022-01-28 10:08:16 +080067 private static boolean sInitialized = false;
Wayne Ma0ea3bdc2022-01-12 01:12:11 +080068
Motomu Utsumi18b287d2022-06-19 10:45:30 +000069 // Lock for sConfigurationMap entry for UID_RULES_CONFIGURATION_KEY.
70 // This entry is not accessed by others.
71 // BpfNetMaps acquires this lock while sequence of read, modify, and write.
72 private static final Object sUidRulesConfigBpfMapLock = new Object();
73
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +000074 private static final String CONFIGURATION_MAP_PATH =
75 "/sys/fs/bpf/netd_shared/map_netd_configuration_map";
Motomu Utsumi5a68a212022-06-24 10:14:31 +000076 private static final String UID_OWNER_MAP_PATH =
77 "/sys/fs/bpf/netd_shared/map_netd_uid_owner_map";
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +000078 private static final U32 UID_RULES_CONFIGURATION_KEY = new U32(0);
79 private static BpfMap<U32, U32> sConfigurationMap = null;
Motomu Utsumi5a68a212022-06-24 10:14:31 +000080 // BpfMap for UID_OWNER_MAP_PATH. This map is not accessed by others.
81 private static BpfMap<U32, UidOwnerValue> sUidOwnerMap = null;
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +000082
83 // LINT.IfChange(match_type)
Motomu Utsumi60ed3be2022-06-24 10:38:57 +000084 @VisibleForTesting public static final long NO_MATCH = 0;
85 @VisibleForTesting public static final long HAPPY_BOX_MATCH = (1 << 0);
86 @VisibleForTesting public static final long PENALTY_BOX_MATCH = (1 << 1);
87 @VisibleForTesting public static final long DOZABLE_MATCH = (1 << 2);
88 @VisibleForTesting public static final long STANDBY_MATCH = (1 << 3);
89 @VisibleForTesting public static final long POWERSAVE_MATCH = (1 << 4);
90 @VisibleForTesting public static final long RESTRICTED_MATCH = (1 << 5);
91 @VisibleForTesting public static final long LOW_POWER_STANDBY_MATCH = (1 << 6);
92 @VisibleForTesting public static final long IIF_MATCH = (1 << 7);
93 @VisibleForTesting public static final long LOCKDOWN_VPN_MATCH = (1 << 8);
94 @VisibleForTesting public static final long OEM_DENY_1_MATCH = (1 << 9);
95 @VisibleForTesting public static final long OEM_DENY_2_MATCH = (1 << 10);
96 @VisibleForTesting public static final long OEM_DENY_3_MATCH = (1 << 11);
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +000097 // LINT.ThenChange(packages/modules/Connectivity/bpf_progs/bpf_shared.h)
98
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +000099 /**
Motomu Utsumi305975f2022-06-27 09:24:32 +0000100 * Set configurationMap for test.
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000101 */
102 @VisibleForTesting
Motomu Utsumi305975f2022-06-27 09:24:32 +0000103 public static void setConfigurationMapForTest(BpfMap<U32, U32> configurationMap) {
104 sConfigurationMap = configurationMap;
105 }
106
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000107 /**
108 * Set uidOwnerMap for test.
109 */
110 @VisibleForTesting
111 public static void setUidOwnerMapForTest(BpfMap<U32, UidOwnerValue> uidOwnerMap) {
112 sUidOwnerMap = uidOwnerMap;
113 }
114
Motomu Utsumi305975f2022-06-27 09:24:32 +0000115 private static BpfMap<U32, U32> getConfigurationMap() {
116 try {
117 return new BpfMap<>(
118 CONFIGURATION_MAP_PATH, BpfMap.BPF_F_RDWR, U32.class, U32.class);
119 } catch (ErrnoException e) {
120 throw new IllegalStateException("Cannot open netd configuration map", e);
121 }
122 }
123
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000124 private static BpfMap<U32, UidOwnerValue> getUidOwnerMap() {
125 try {
126 return new BpfMap<>(
127 UID_OWNER_MAP_PATH, BpfMap.BPF_F_RDWR, U32.class, UidOwnerValue.class);
128 } catch (ErrnoException e) {
129 throw new IllegalStateException("Cannot open uid owner map", e);
130 }
131 }
132
Motomu Utsumi305975f2022-06-27 09:24:32 +0000133 private static void setBpfMaps() {
134 if (sConfigurationMap == null) {
135 sConfigurationMap = getConfigurationMap();
136 }
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000137 if (sUidOwnerMap == null) {
138 sUidOwnerMap = getUidOwnerMap();
139 }
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000140 }
141
Ken Chenf5f51332022-01-28 10:08:16 +0800142 /**
143 * Initializes the class if it is not already initialized. This method will open maps but not
144 * cause any other effects. This method may be called multiple times on any thread.
145 */
146 private static synchronized void ensureInitialized() {
147 if (sInitialized) return;
Motomu Utsumi305975f2022-06-27 09:24:32 +0000148 setBpfMaps();
149 native_init();
Ken Chenf5f51332022-01-28 10:08:16 +0800150 sInitialized = true;
Wayne Ma2fde98c2022-01-17 18:04:05 +0800151 }
152
Motomu Utsumi5f52f4f2022-06-30 03:31:09 +0000153 /**
154 * Dependencies of BpfNetMaps, for injection in tests.
155 */
156 @VisibleForTesting
157 public static class Dependencies {
158 /**
159 * Get interface index.
160 */
161 public int getIfIndex(final String ifName) {
162 return Os.if_nametoindex(ifName);
163 }
164 }
165
markchien49e944c2022-03-01 15:22:20 +0800166 /** Constructor used after T that doesn't need to use netd anymore. */
167 public BpfNetMaps() {
168 this(null);
169
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000170 if (PRE_T) throw new IllegalArgumentException("BpfNetMaps need to use netd before T");
markchien49e944c2022-03-01 15:22:20 +0800171 }
172
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000173 public BpfNetMaps(final INetd netd) {
Motomu Utsumi5f52f4f2022-06-30 03:31:09 +0000174 this(netd, new Dependencies());
175 }
176
177 @VisibleForTesting
178 public BpfNetMaps(final INetd netd, final Dependencies deps) {
Motomu Utsumi305975f2022-06-27 09:24:32 +0000179 if (!PRE_T) {
180 ensureInitialized();
181 }
Wayne Ma2fde98c2022-01-17 18:04:05 +0800182 mNetd = netd;
Motomu Utsumi5f52f4f2022-06-30 03:31:09 +0000183 mDeps = deps;
Wayne Ma790c83e2022-01-13 10:35:05 +0800184 }
185
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000186 /**
187 * Get corresponding match from firewall chain.
188 */
189 @VisibleForTesting
190 public long getMatchByFirewallChain(final int chain) {
Motomu Utsumi40230be2022-07-05 03:27:35 +0000191 switch (chain) {
192 case FIREWALL_CHAIN_DOZABLE:
193 return DOZABLE_MATCH;
194 case FIREWALL_CHAIN_STANDBY:
195 return STANDBY_MATCH;
196 case FIREWALL_CHAIN_POWERSAVE:
197 return POWERSAVE_MATCH;
198 case FIREWALL_CHAIN_RESTRICTED:
199 return RESTRICTED_MATCH;
200 case FIREWALL_CHAIN_LOW_POWER_STANDBY:
201 return LOW_POWER_STANDBY_MATCH;
202 case FIREWALL_CHAIN_OEM_DENY_1:
203 return OEM_DENY_1_MATCH;
204 case FIREWALL_CHAIN_OEM_DENY_2:
205 return OEM_DENY_2_MATCH;
206 case FIREWALL_CHAIN_OEM_DENY_3:
207 return OEM_DENY_3_MATCH;
208 default:
209 throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain);
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000210 }
Motomu Utsumi40230be2022-07-05 03:27:35 +0000211 }
212
213 /**
214 * Get if the chain is allow list or not.
215 *
216 * ALLOWLIST means the firewall denies all by default, uids must be explicitly allowed
217 * DENYLIST means the firewall allows all by default, uids must be explicitly denyed
218 */
219 @VisibleForTesting
220 public boolean isFirewallAllowList(final int chain) {
221 switch (chain) {
222 case FIREWALL_CHAIN_DOZABLE:
223 case FIREWALL_CHAIN_POWERSAVE:
224 case FIREWALL_CHAIN_RESTRICTED:
225 case FIREWALL_CHAIN_LOW_POWER_STANDBY:
226 return true;
227 case FIREWALL_CHAIN_STANDBY:
228 case FIREWALL_CHAIN_OEM_DENY_1:
229 case FIREWALL_CHAIN_OEM_DENY_2:
230 case FIREWALL_CHAIN_OEM_DENY_3:
231 return false;
232 default:
233 throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain);
234 }
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000235 }
236
Ken Chenf5f51332022-01-28 10:08:16 +0800237 private void maybeThrow(final int err, final String msg) {
238 if (err != 0) {
239 throw new ServiceSpecificException(err, msg + ": " + Os.strerror(err));
240 }
241 }
242
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000243 private void throwIfPreT(final String msg) {
244 if (PRE_T) {
Motomu Utsumi18b287d2022-06-19 10:45:30 +0000245 throw new UnsupportedOperationException(msg);
246 }
247 }
248
Motomu Utsumi60ed3be2022-06-24 10:38:57 +0000249 private void removeRule(final int uid, final long match, final String caller) {
250 try {
251 synchronized (sUidOwnerMap) {
252 final UidOwnerValue oldMatch = sUidOwnerMap.getValue(new U32(uid));
253
254 if (oldMatch == null) {
255 throw new ServiceSpecificException(ENOENT,
256 "sUidOwnerMap does not have entry for uid: " + uid);
257 }
258
259 final UidOwnerValue newMatch = new UidOwnerValue(
260 (match == IIF_MATCH) ? 0 : oldMatch.iif,
261 oldMatch.rule & ~match
262 );
263
264 if (newMatch.rule == 0) {
265 sUidOwnerMap.deleteEntry(new U32(uid));
266 } else {
267 sUidOwnerMap.updateEntry(new U32(uid), newMatch);
268 }
269 }
270 } catch (ErrnoException e) {
271 throw new ServiceSpecificException(e.errno,
272 caller + " failed to remove rule: " + Os.strerror(e.errno));
273 }
274 }
275
Motomu Utsumi389278e2022-06-28 07:05:05 +0000276 private void addRule(final int uid, final long match, final long iif, final String caller) {
277 if (match != IIF_MATCH && iif != 0) {
278 throw new ServiceSpecificException(EINVAL,
279 "Non-interface match must have zero interface index");
280 }
281
282 try {
283 synchronized (sUidOwnerMap) {
284 final UidOwnerValue oldMatch = sUidOwnerMap.getValue(new U32(uid));
285
286 final UidOwnerValue newMatch;
287 if (oldMatch != null) {
288 newMatch = new UidOwnerValue(
289 (match == IIF_MATCH) ? iif : oldMatch.iif,
290 oldMatch.rule | match
291 );
292 } else {
293 newMatch = new UidOwnerValue(
294 iif,
295 match
296 );
297 }
298 sUidOwnerMap.updateEntry(new U32(uid), newMatch);
299 }
300 } catch (ErrnoException e) {
301 throw new ServiceSpecificException(e.errno,
302 caller + " failed to add rule: " + Os.strerror(e.errno));
303 }
304 }
305
306 private void addRule(final int uid, final long match, final String caller) {
307 addRule(uid, match, 0 /* iif */, caller);
308 }
309
Ken Chenf5f51332022-01-28 10:08:16 +0800310 /**
311 * Add naughty app bandwidth rule for specific app
312 *
313 * @param uid uid of target app
Ken Chenf5f51332022-01-28 10:08:16 +0800314 * @throws ServiceSpecificException in case of failure, with an error code indicating the
315 * cause of the failure.
316 */
Lorenzo Colitti82244fd2022-03-04 23:15:00 +0900317 public void addNaughtyApp(final int uid) {
Motomu Utsumi389278e2022-06-28 07:05:05 +0000318 throwIfPreT("addNaughtyApp is not available on pre-T devices");
319 addRule(uid, PENALTY_BOX_MATCH, "addNaughtyApp");
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800320 }
321
Ken Chenf5f51332022-01-28 10:08:16 +0800322 /**
323 * Remove naughty app bandwidth rule for specific app
324 *
325 * @param uid uid of target app
Ken Chenf5f51332022-01-28 10:08:16 +0800326 * @throws ServiceSpecificException in case of failure, with an error code indicating the
327 * cause of the failure.
328 */
Lorenzo Colitti82244fd2022-03-04 23:15:00 +0900329 public void removeNaughtyApp(final int uid) {
Motomu Utsumi60ed3be2022-06-24 10:38:57 +0000330 throwIfPreT("removeNaughtyApp is not available on pre-T devices");
331 removeRule(uid, PENALTY_BOX_MATCH, "removeNaughtyApp");
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800332 }
333
Ken Chenf5f51332022-01-28 10:08:16 +0800334 /**
335 * Add nice app bandwidth rule for specific app
336 *
337 * @param uid uid of target app
Ken Chenf5f51332022-01-28 10:08:16 +0800338 * @throws ServiceSpecificException in case of failure, with an error code indicating the
339 * cause of the failure.
340 */
Lorenzo Colitti82244fd2022-03-04 23:15:00 +0900341 public void addNiceApp(final int uid) {
Motomu Utsumi55630d02022-06-29 07:46:52 +0000342 throwIfPreT("addNiceApp is not available on pre-T devices");
343 addRule(uid, HAPPY_BOX_MATCH, "addNiceApp");
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800344 }
345
Ken Chenf5f51332022-01-28 10:08:16 +0800346 /**
347 * Remove nice app bandwidth rule for specific app
348 *
349 * @param uid uid of target app
Ken Chenf5f51332022-01-28 10:08:16 +0800350 * @throws ServiceSpecificException in case of failure, with an error code indicating the
351 * cause of the failure.
352 */
Lorenzo Colitti82244fd2022-03-04 23:15:00 +0900353 public void removeNiceApp(final int uid) {
Motomu Utsumi7392eb42022-06-29 03:53:03 +0000354 throwIfPreT("removeNiceApp is not available on pre-T devices");
355 removeRule(uid, HAPPY_BOX_MATCH, "removeNiceApp");
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800356 }
357
Ken Chenf5f51332022-01-28 10:08:16 +0800358 /**
359 * Set target firewall child chain
360 *
361 * @param childChain target chain to enable
362 * @param enable whether to enable or disable child chain.
Motomu Utsumi18b287d2022-06-19 10:45:30 +0000363 * @throws UnsupportedOperationException if called on pre-T devices.
Ken Chenf5f51332022-01-28 10:08:16 +0800364 * @throws ServiceSpecificException in case of failure, with an error code indicating the
365 * cause of the failure.
366 */
Lorenzo Colitti82244fd2022-03-04 23:15:00 +0900367 public void setChildChain(final int childChain, final boolean enable) {
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000368 throwIfPreT("setChildChain is not available on pre-T devices");
Motomu Utsumi18b287d2022-06-19 10:45:30 +0000369
370 final long match = getMatchByFirewallChain(childChain);
371 try {
372 synchronized (sUidRulesConfigBpfMapLock) {
373 final U32 config = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY);
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000374 final long newConfig = enable ? (config.val | match) : (config.val & ~match);
Motomu Utsumi18b287d2022-06-19 10:45:30 +0000375 sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(newConfig));
376 }
377 } catch (ErrnoException e) {
378 throw new ServiceSpecificException(e.errno,
379 "Unable to set child chain: " + Os.strerror(e.errno));
380 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800381 }
382
383 /**
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000384 * Get the specified firewall chain's status.
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000385 *
386 * @param childChain target chain
387 * @return {@code true} if chain is enabled, {@code false} if chain is not enabled.
388 * @throws UnsupportedOperationException if called on pre-T devices.
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000389 * @throws ServiceSpecificException in case of failure, with an error code indicating the
390 * cause of the failure.
391 */
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000392 public boolean isChainEnabled(final int childChain) {
393 throwIfPreT("isChainEnabled is not available on pre-T devices");
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000394
395 final long match = getMatchByFirewallChain(childChain);
396 try {
397 final U32 config = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY);
Motomu Utsumibe3ff1e2022-06-08 10:05:07 +0000398 return (config.val & match) != 0;
399 } catch (ErrnoException e) {
400 throw new ServiceSpecificException(e.errno,
401 "Unable to get firewall chain status: " + Os.strerror(e.errno));
402 }
403 }
404
405 /**
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800406 * Replaces the contents of the specified UID-based firewall chain.
407 *
408 * The chain may be an allowlist chain or a denylist chain. A denylist chain contains DROP
409 * rules for the specified UIDs and a RETURN rule at the end. An allowlist chain contains RETURN
Ken Chenf5f51332022-01-28 10:08:16 +0800410 * rules for the system UID range (0 to {@code UID_APP} - 1), RETURN rules for the specified
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800411 * UIDs, and a DROP rule at the end. The chain will be created if it does not exist.
412 *
Ken Chenf5f51332022-01-28 10:08:16 +0800413 * @param chainName The name of the chain to replace.
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800414 * @param isAllowlist Whether this is an allowlist or denylist chain.
Ken Chenf5f51332022-01-28 10:08:16 +0800415 * @param uids The list of UIDs to allow/deny.
416 * @return 0 if the chain was successfully replaced, errno otherwise.
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800417 */
418 public int replaceUidChain(final String chainName, final boolean isAllowlist,
Lorenzo Colitti82244fd2022-03-04 23:15:00 +0900419 final int[] uids) {
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000420 synchronized (sUidOwnerMap) {
421 final int err = native_replaceUidChain(chainName, isAllowlist, uids);
422 if (err != 0) {
423 Log.e(TAG, "replaceUidChain failed: " + Os.strerror(-err));
424 }
425 return -err;
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800426 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800427 }
428
Ken Chenf5f51332022-01-28 10:08:16 +0800429 /**
430 * Set firewall rule for uid
431 *
432 * @param childChain target chain
433 * @param uid uid to allow/deny
434 * @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY
Ken Chenf5f51332022-01-28 10:08:16 +0800435 * @throws ServiceSpecificException in case of failure, with an error code indicating the
436 * cause of the failure.
437 */
Lorenzo Colitti82244fd2022-03-04 23:15:00 +0900438 public void setUidRule(final int childChain, final int uid, final int firewallRule) {
Motomu Utsumi40230be2022-07-05 03:27:35 +0000439 throwIfPreT("setUidRule is not available on pre-T devices");
440
441 final long match = getMatchByFirewallChain(childChain);
442 final boolean isAllowList = isFirewallAllowList(childChain);
443 final boolean add = (firewallRule == FIREWALL_RULE_ALLOW && isAllowList)
444 || (firewallRule == FIREWALL_RULE_DENY && !isAllowList);
445
446 if (add) {
447 addRule(uid, match, "setUidRule");
448 } else {
449 removeRule(uid, match, "setUidRule");
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000450 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800451 }
452
453 /**
454 * Add ingress interface filtering rules to a list of UIDs
455 *
456 * For a given uid, once a filtering rule is added, the kernel will only allow packets from the
457 * allowed interface and loopback to be sent to the list of UIDs.
458 *
459 * Calling this method on one or more UIDs with an existing filtering rule but a different
460 * interface name will result in the filtering rule being updated to allow the new interface
461 * instead. Otherwise calling this method will not affect existing rules set on other UIDs.
462 *
463 * @param ifName the name of the interface on which the filtering rules will allow packets to
Ken Chenf5f51332022-01-28 10:08:16 +0800464 * be received.
465 * @param uids an array of UIDs which the filtering rules will be set
466 * @throws RemoteException when netd has crashed.
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800467 * @throws ServiceSpecificException in case of failure, with an error code indicating the
Ken Chenf5f51332022-01-28 10:08:16 +0800468 * cause of the failure.
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800469 */
Ken Chenf5f51332022-01-28 10:08:16 +0800470 public void addUidInterfaceRules(final String ifName, final int[] uids) throws RemoteException {
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000471 if (PRE_T) {
Ken Chenf5f51332022-01-28 10:08:16 +0800472 mNetd.firewallAddUidInterfaceRules(ifName, uids);
Wayne Ma2fde98c2022-01-17 18:04:05 +0800473 return;
474 }
Motomu Utsumi5f52f4f2022-06-30 03:31:09 +0000475 // Null ifName is a wildcard to allow apps to receive packets on all interfaces and ifIndex
476 // is set to 0.
477 final int ifIndex;
478 if (ifName == null) {
479 ifIndex = 0;
480 } else {
481 ifIndex = mDeps.getIfIndex(ifName);
482 if (ifIndex == 0) {
483 throw new ServiceSpecificException(ENODEV,
484 "Failed to get index of interface " + ifName);
485 }
486 }
487 for (final int uid: uids) {
488 try {
489 addRule(uid, IIF_MATCH, ifIndex, "addUidInterfaceRules");
490 } catch (ServiceSpecificException e) {
491 Log.e(TAG, "addRule failed uid=" + uid + " ifName=" + ifName + ", " + e);
492 }
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000493 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800494 }
495
496 /**
497 * Remove ingress interface filtering rules from a list of UIDs
498 *
499 * Clear the ingress interface filtering rules from the list of UIDs which were previously set
500 * by addUidInterfaceRules(). Ignore any uid which does not have filtering rule.
501 *
502 * @param uids an array of UIDs from which the filtering rules will be removed
Ken Chenf5f51332022-01-28 10:08:16 +0800503 * @throws RemoteException when netd has crashed.
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800504 * @throws ServiceSpecificException in case of failure, with an error code indicating the
Ken Chenf5f51332022-01-28 10:08:16 +0800505 * cause of the failure.
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800506 */
Ken Chenf5f51332022-01-28 10:08:16 +0800507 public void removeUidInterfaceRules(final int[] uids) throws RemoteException {
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000508 if (PRE_T) {
Ken Chenf5f51332022-01-28 10:08:16 +0800509 mNetd.firewallRemoveUidInterfaceRules(uids);
Wayne Ma2fde98c2022-01-17 18:04:05 +0800510 return;
511 }
Motomu Utsumi599c4e52022-06-30 03:37:18 +0000512 for (final int uid: uids) {
513 try {
514 removeRule(uid, IIF_MATCH, "removeUidInterfaceRules");
515 } catch (ServiceSpecificException e) {
516 Log.e(TAG, "removeRule failed uid=" + uid + ", " + e);
517 }
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000518 }
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800519 }
520
Ken Chenf5f51332022-01-28 10:08:16 +0800521 /**
Motomu Utsumi8b42e6d2022-05-19 06:23:40 +0000522 * Update lockdown rule for uid
523 *
524 * @param uid target uid to add/remove the rule
525 * @param add {@code true} to add the rule, {@code false} to remove the rule.
526 * @throws ServiceSpecificException in case of failure, with an error code indicating the
527 * cause of the failure.
528 */
529 public void updateUidLockdownRule(final int uid, final boolean add) {
Motomu Utsumi697b2992022-06-30 02:25:29 +0000530 throwIfPreT("updateUidLockdownRule is not available on pre-T devices");
531 if (add) {
532 addRule(uid, LOCKDOWN_VPN_MATCH, "updateUidLockdownRule");
533 } else {
534 removeRule(uid, LOCKDOWN_VPN_MATCH, "updateUidLockdownRule");
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000535 }
Motomu Utsumi8b42e6d2022-05-19 06:23:40 +0000536 }
537
538 /**
Ken Chenf5f51332022-01-28 10:08:16 +0800539 * Request netd to change the current active network stats map.
540 *
Ken Chenf5f51332022-01-28 10:08:16 +0800541 * @throws ServiceSpecificException in case of failure, with an error code indicating the
542 * cause of the failure.
543 */
markchien49e944c2022-03-01 15:22:20 +0800544 public void swapActiveStatsMap() {
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800545 final int err = native_swapActiveStatsMap();
Ken Chenf5f51332022-01-28 10:08:16 +0800546 maybeThrow(err, "Unable to swap active stats map");
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800547 }
548
Ken Chenf5f51332022-01-28 10:08:16 +0800549 /**
550 * Assigns android.permission.INTERNET and/or android.permission.UPDATE_DEVICE_STATS to the uids
551 * specified. Or remove all permissions from the uids.
552 *
553 * @param permissions The permission to grant, it could be either PERMISSION_INTERNET and/or
554 * PERMISSION_UPDATE_DEVICE_STATS. If the permission is NO_PERMISSIONS, then
555 * revoke all permissions for the uids.
556 * @param uids uid of users to grant permission
557 * @throws RemoteException when netd has crashed.
558 */
559 public void setNetPermForUids(final int permissions, final int[] uids) throws RemoteException {
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000560 if (PRE_T) {
Ken Chenf5f51332022-01-28 10:08:16 +0800561 mNetd.trafficSetNetPermForUids(permissions, uids);
Wayne Ma2fde98c2022-01-17 18:04:05 +0800562 return;
563 }
564 native_setPermissionForUids(permissions, uids);
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800565 }
566
Ken Chene6d511f2022-01-25 11:10:42 +0800567 /**
568 * Dump BPF maps
569 *
570 * @param fd file descriptor to output
571 * @throws IOException when file descriptor is invalid.
572 * @throws ServiceSpecificException when the method is called on an unsupported device.
573 */
574 public void dump(final FileDescriptor fd, boolean verbose)
575 throws IOException, ServiceSpecificException {
Motomu Utsumi25cf86f2022-06-27 08:50:19 +0000576 if (PRE_T) {
Ken Chene6d511f2022-01-25 11:10:42 +0800577 throw new ServiceSpecificException(
578 EOPNOTSUPP, "dumpsys connectivity trafficcontroller dump not available on pre-T"
579 + " devices, use dumpsys netd trafficcontroller instead.");
580 }
581 native_dump(fd, verbose);
582 }
583
Wayne Ma790c83e2022-01-13 10:35:05 +0800584 private static native void native_init();
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000585 @GuardedBy("sUidOwnerMap")
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800586 private native int native_addNaughtyApp(int uid);
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000587 @GuardedBy("sUidOwnerMap")
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800588 private native int native_removeNaughtyApp(int uid);
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000589 @GuardedBy("sUidOwnerMap")
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800590 private native int native_addNiceApp(int uid);
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000591 @GuardedBy("sUidOwnerMap")
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800592 private native int native_removeNiceApp(int uid);
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000593 @GuardedBy("sUidOwnerMap")
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800594 private native int native_replaceUidChain(String name, boolean isAllowlist, int[] uids);
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000595 @GuardedBy("sUidOwnerMap")
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800596 private native int native_setUidRule(int childChain, int uid, int firewallRule);
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000597 @GuardedBy("sUidOwnerMap")
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800598 private native int native_addUidInterfaceRules(String ifName, int[] uids);
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000599 @GuardedBy("sUidOwnerMap")
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800600 private native int native_removeUidInterfaceRules(int[] uids);
Motomu Utsumi5a68a212022-06-24 10:14:31 +0000601 @GuardedBy("sUidOwnerMap")
Motomu Utsumi8b42e6d2022-05-19 06:23:40 +0000602 private native int native_updateUidLockdownRule(int uid, boolean add);
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800603 private native int native_swapActiveStatsMap();
Wayne Ma2fde98c2022-01-17 18:04:05 +0800604 private native void native_setPermissionForUids(int permissions, int[] uids);
Ken Chene6d511f2022-01-25 11:10:42 +0800605 private native void native_dump(FileDescriptor fd, boolean verbose);
Wayne Ma0ea3bdc2022-01-12 01:12:11 +0800606}