1 /* 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 17 package com.android.server; 18 19 import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE; 20 import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY; 21 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1; 22 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2; 23 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3; 24 import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE; 25 import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED; 26 import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY; 27 import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW; 28 import static android.net.ConnectivityManager.FIREWALL_RULE_DENY; 29 import static android.net.INetd.PERMISSION_INTERNET; 30 import static android.net.INetd.PERMISSION_NONE; 31 import static android.net.INetd.PERMISSION_UNINSTALLED; 32 import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS; 33 import static android.system.OsConstants.EINVAL; 34 import static android.system.OsConstants.ENODEV; 35 import static android.system.OsConstants.ENOENT; 36 import static android.system.OsConstants.EOPNOTSUPP; 37 38 import static com.android.server.ConnectivityStatsLog.NETWORK_BPF_MAP_INFO; 39 40 import android.app.StatsManager; 41 import android.content.Context; 42 import android.net.INetd; 43 import android.os.RemoteException; 44 import android.os.ServiceSpecificException; 45 import android.provider.DeviceConfig; 46 import android.system.ErrnoException; 47 import android.system.Os; 48 import android.util.ArraySet; 49 import android.util.IndentingPrintWriter; 50 import android.util.Log; 51 import android.util.Pair; 52 import android.util.StatsEvent; 53 54 import com.android.internal.annotations.VisibleForTesting; 55 import com.android.modules.utils.BackgroundThread; 56 import com.android.modules.utils.build.SdkLevel; 57 import com.android.net.module.util.BpfDump; 58 import com.android.net.module.util.BpfMap; 59 import com.android.net.module.util.DeviceConfigUtils; 60 import com.android.net.module.util.IBpfMap; 61 import com.android.net.module.util.Struct; 62 import com.android.net.module.util.Struct.S32; 63 import com.android.net.module.util.Struct.U32; 64 import com.android.net.module.util.Struct.U8; 65 import com.android.net.module.util.bpf.CookieTagMapKey; 66 import com.android.net.module.util.bpf.CookieTagMapValue; 67 68 import java.io.FileDescriptor; 69 import java.io.IOException; 70 import java.util.Arrays; 71 import java.util.List; 72 import java.util.Set; 73 import java.util.StringJoiner; 74 75 /** 76 * BpfNetMaps is responsible for providing traffic controller relevant functionality. 77 * 78 * {@hide} 79 */ 80 public class BpfNetMaps { 81 private static final boolean PRE_T = !SdkLevel.isAtLeastT(); 82 static { 83 if (!PRE_T) { 84 System.loadLibrary("service-connectivity"); 85 } 86 } 87 88 private static final String TAG = "BpfNetMaps"; 89 private final INetd mNetd; 90 private final Dependencies mDeps; 91 // Use legacy netd for releases before T. 92 private static boolean sInitialized = false; 93 94 private static Boolean sEnableJavaBpfMap = null; 95 private static final String BPF_NET_MAPS_ENABLE_JAVA_BPF_MAP = 96 "bpf_net_maps_enable_java_bpf_map"; 97 98 // Lock for sConfigurationMap entry for UID_RULES_CONFIGURATION_KEY. 99 // This entry is not accessed by others. 100 // BpfNetMaps acquires this lock while sequence of read, modify, and write. 101 private static final Object sUidRulesConfigBpfMapLock = new Object(); 102 103 // Lock for sConfigurationMap entry for CURRENT_STATS_MAP_CONFIGURATION_KEY. 104 // BpfNetMaps acquires this lock while sequence of read, modify, and write. 105 // BpfNetMaps is an only writer of this entry. 106 private static final Object sCurrentStatsMapConfigLock = new Object(); 107 108 private static final String CONFIGURATION_MAP_PATH = 109 "/sys/fs/bpf/netd_shared/map_netd_configuration_map"; 110 private static final String UID_OWNER_MAP_PATH = 111 "/sys/fs/bpf/netd_shared/map_netd_uid_owner_map"; 112 private static final String UID_PERMISSION_MAP_PATH = 113 "/sys/fs/bpf/netd_shared/map_netd_uid_permission_map"; 114 private static final String COOKIE_TAG_MAP_PATH = 115 "/sys/fs/bpf/netd_shared/map_netd_cookie_tag_map"; 116 private static final S32 UID_RULES_CONFIGURATION_KEY = new S32(0); 117 private static final S32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new S32(1); 118 private static final long UID_RULES_DEFAULT_CONFIGURATION = 0; 119 private static final long STATS_SELECT_MAP_A = 0; 120 private static final long STATS_SELECT_MAP_B = 1; 121 122 private static IBpfMap<S32, U32> sConfigurationMap = null; 123 // BpfMap for UID_OWNER_MAP_PATH. This map is not accessed by others. 124 private static IBpfMap<S32, UidOwnerValue> sUidOwnerMap = null; 125 private static IBpfMap<S32, U8> sUidPermissionMap = null; 126 private static IBpfMap<CookieTagMapKey, CookieTagMapValue> sCookieTagMap = null; 127 128 // LINT.IfChange(match_type) 129 @VisibleForTesting public static final long NO_MATCH = 0; 130 @VisibleForTesting public static final long HAPPY_BOX_MATCH = (1 << 0); 131 @VisibleForTesting public static final long PENALTY_BOX_MATCH = (1 << 1); 132 @VisibleForTesting public static final long DOZABLE_MATCH = (1 << 2); 133 @VisibleForTesting public static final long STANDBY_MATCH = (1 << 3); 134 @VisibleForTesting public static final long POWERSAVE_MATCH = (1 << 4); 135 @VisibleForTesting public static final long RESTRICTED_MATCH = (1 << 5); 136 @VisibleForTesting public static final long LOW_POWER_STANDBY_MATCH = (1 << 6); 137 @VisibleForTesting public static final long IIF_MATCH = (1 << 7); 138 @VisibleForTesting public static final long LOCKDOWN_VPN_MATCH = (1 << 8); 139 @VisibleForTesting public static final long OEM_DENY_1_MATCH = (1 << 9); 140 @VisibleForTesting public static final long OEM_DENY_2_MATCH = (1 << 10); 141 @VisibleForTesting public static final long OEM_DENY_3_MATCH = (1 << 11); 142 // LINT.ThenChange(packages/modules/Connectivity/bpf_progs/netd.h) 143 144 private static final List<Pair<Integer, String>> PERMISSION_LIST = Arrays.asList( 145 Pair.create(PERMISSION_INTERNET, "PERMISSION_INTERNET"), 146 Pair.create(PERMISSION_UPDATE_DEVICE_STATS, "PERMISSION_UPDATE_DEVICE_STATS") 147 ); 148 private static final List<Pair<Long, String>> MATCH_LIST = Arrays.asList( 149 Pair.create(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH"), 150 Pair.create(PENALTY_BOX_MATCH, "PENALTY_BOX_MATCH"), 151 Pair.create(DOZABLE_MATCH, "DOZABLE_MATCH"), 152 Pair.create(STANDBY_MATCH, "STANDBY_MATCH"), 153 Pair.create(POWERSAVE_MATCH, "POWERSAVE_MATCH"), 154 Pair.create(RESTRICTED_MATCH, "RESTRICTED_MATCH"), 155 Pair.create(LOW_POWER_STANDBY_MATCH, "LOW_POWER_STANDBY_MATCH"), 156 Pair.create(IIF_MATCH, "IIF_MATCH"), 157 Pair.create(LOCKDOWN_VPN_MATCH, "LOCKDOWN_VPN_MATCH"), 158 Pair.create(OEM_DENY_1_MATCH, "OEM_DENY_1_MATCH"), 159 Pair.create(OEM_DENY_2_MATCH, "OEM_DENY_2_MATCH"), 160 Pair.create(OEM_DENY_3_MATCH, "OEM_DENY_3_MATCH") 161 ); 162 163 /** 164 * Set sEnableJavaBpfMap for test. 165 */ 166 @VisibleForTesting setEnableJavaBpfMapForTest(boolean enable)167 public static void setEnableJavaBpfMapForTest(boolean enable) { 168 sEnableJavaBpfMap = enable; 169 } 170 171 /** 172 * Set configurationMap for test. 173 */ 174 @VisibleForTesting setConfigurationMapForTest(IBpfMap<S32, U32> configurationMap)175 public static void setConfigurationMapForTest(IBpfMap<S32, U32> configurationMap) { 176 sConfigurationMap = configurationMap; 177 } 178 179 /** 180 * Set uidOwnerMap for test. 181 */ 182 @VisibleForTesting setUidOwnerMapForTest(IBpfMap<S32, UidOwnerValue> uidOwnerMap)183 public static void setUidOwnerMapForTest(IBpfMap<S32, UidOwnerValue> uidOwnerMap) { 184 sUidOwnerMap = uidOwnerMap; 185 } 186 187 /** 188 * Set uidPermissionMap for test. 189 */ 190 @VisibleForTesting setUidPermissionMapForTest(IBpfMap<S32, U8> uidPermissionMap)191 public static void setUidPermissionMapForTest(IBpfMap<S32, U8> uidPermissionMap) { 192 sUidPermissionMap = uidPermissionMap; 193 } 194 195 /** 196 * Set cookieTagMap for test. 197 */ 198 @VisibleForTesting setCookieTagMapForTest( IBpfMap<CookieTagMapKey, CookieTagMapValue> cookieTagMap)199 public static void setCookieTagMapForTest( 200 IBpfMap<CookieTagMapKey, CookieTagMapValue> cookieTagMap) { 201 sCookieTagMap = cookieTagMap; 202 } 203 getConfigurationMap()204 private static IBpfMap<S32, U32> getConfigurationMap() { 205 try { 206 return new BpfMap<>( 207 CONFIGURATION_MAP_PATH, BpfMap.BPF_F_RDWR, S32.class, U32.class); 208 } catch (ErrnoException e) { 209 throw new IllegalStateException("Cannot open netd configuration map", e); 210 } 211 } 212 getUidOwnerMap()213 private static IBpfMap<S32, UidOwnerValue> getUidOwnerMap() { 214 try { 215 return new BpfMap<>( 216 UID_OWNER_MAP_PATH, BpfMap.BPF_F_RDWR, S32.class, UidOwnerValue.class); 217 } catch (ErrnoException e) { 218 throw new IllegalStateException("Cannot open uid owner map", e); 219 } 220 } 221 getUidPermissionMap()222 private static IBpfMap<S32, U8> getUidPermissionMap() { 223 try { 224 return new BpfMap<>( 225 UID_PERMISSION_MAP_PATH, BpfMap.BPF_F_RDWR, S32.class, U8.class); 226 } catch (ErrnoException e) { 227 throw new IllegalStateException("Cannot open uid permission map", e); 228 } 229 } 230 getCookieTagMap()231 private static IBpfMap<CookieTagMapKey, CookieTagMapValue> getCookieTagMap() { 232 try { 233 return new BpfMap<>(COOKIE_TAG_MAP_PATH, BpfMap.BPF_F_RDWR, 234 CookieTagMapKey.class, CookieTagMapValue.class); 235 } catch (ErrnoException e) { 236 throw new IllegalStateException("Cannot open cookie tag map", e); 237 } 238 } 239 initBpfMaps()240 private static void initBpfMaps() { 241 if (sConfigurationMap == null) { 242 sConfigurationMap = getConfigurationMap(); 243 } 244 try { 245 sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, 246 new U32(UID_RULES_DEFAULT_CONFIGURATION)); 247 } catch (ErrnoException e) { 248 throw new IllegalStateException("Failed to initialize uid rules configuration", e); 249 } 250 try { 251 sConfigurationMap.updateEntry(CURRENT_STATS_MAP_CONFIGURATION_KEY, 252 new U32(STATS_SELECT_MAP_A)); 253 } catch (ErrnoException e) { 254 throw new IllegalStateException("Failed to initialize current stats configuration", e); 255 } 256 257 if (sUidOwnerMap == null) { 258 sUidOwnerMap = getUidOwnerMap(); 259 } 260 try { 261 sUidOwnerMap.clear(); 262 } catch (ErrnoException e) { 263 throw new IllegalStateException("Failed to initialize uid owner map", e); 264 } 265 266 if (sUidPermissionMap == null) { 267 sUidPermissionMap = getUidPermissionMap(); 268 } 269 270 if (sCookieTagMap == null) { 271 sCookieTagMap = getCookieTagMap(); 272 } 273 } 274 275 /** 276 * Initializes the class if it is not already initialized. This method will open maps but not 277 * cause any other effects. This method may be called multiple times on any thread. 278 */ ensureInitialized(final Context context)279 private static synchronized void ensureInitialized(final Context context) { 280 if (sInitialized) return; 281 if (sEnableJavaBpfMap == null) { 282 sEnableJavaBpfMap = SdkLevel.isAtLeastU() || 283 DeviceConfigUtils.isFeatureEnabled(context, 284 DeviceConfig.NAMESPACE_TETHERING, BPF_NET_MAPS_ENABLE_JAVA_BPF_MAP, 285 DeviceConfigUtils.TETHERING_MODULE_NAME, false /* defaultValue */); 286 } 287 Log.d(TAG, "BpfNetMaps is initialized with sEnableJavaBpfMap=" + sEnableJavaBpfMap); 288 289 initBpfMaps(); 290 native_init(!sEnableJavaBpfMap /* startSkDestroyListener */); 291 sInitialized = true; 292 } 293 isSkDestroyListenerRunning()294 public boolean isSkDestroyListenerRunning() { 295 return !sEnableJavaBpfMap; 296 } 297 298 /** 299 * Dependencies of BpfNetMaps, for injection in tests. 300 */ 301 @VisibleForTesting 302 public static class Dependencies { 303 /** 304 * Get interface index. 305 */ getIfIndex(final String ifName)306 public int getIfIndex(final String ifName) { 307 return Os.if_nametoindex(ifName); 308 } 309 310 /** 311 * Call synchronize_rcu() 312 */ synchronizeKernelRCU()313 public int synchronizeKernelRCU() { 314 return native_synchronizeKernelRCU(); 315 } 316 317 /** 318 * Build Stats Event for NETWORK_BPF_MAP_INFO atom 319 */ buildStatsEvent(final int cookieTagMapSize, final int uidOwnerMapSize, final int uidPermissionMapSize)320 public StatsEvent buildStatsEvent(final int cookieTagMapSize, final int uidOwnerMapSize, 321 final int uidPermissionMapSize) { 322 return ConnectivityStatsLog.buildStatsEvent(NETWORK_BPF_MAP_INFO, cookieTagMapSize, 323 uidOwnerMapSize, uidPermissionMapSize); 324 } 325 326 /** 327 * Call native_dump 328 */ nativeDump(final FileDescriptor fd, final boolean verbose)329 public void nativeDump(final FileDescriptor fd, final boolean verbose) { 330 native_dump(fd, verbose); 331 } 332 } 333 334 /** Constructor used after T that doesn't need to use netd anymore. */ BpfNetMaps(final Context context)335 public BpfNetMaps(final Context context) { 336 this(context, null); 337 338 if (PRE_T) throw new IllegalArgumentException("BpfNetMaps need to use netd before T"); 339 } 340 BpfNetMaps(final Context context, final INetd netd)341 public BpfNetMaps(final Context context, final INetd netd) { 342 this(context, netd, new Dependencies()); 343 } 344 345 @VisibleForTesting BpfNetMaps(final Context context, final INetd netd, final Dependencies deps)346 public BpfNetMaps(final Context context, final INetd netd, final Dependencies deps) { 347 if (!PRE_T) { 348 ensureInitialized(context); 349 } 350 mNetd = netd; 351 mDeps = deps; 352 } 353 354 /** 355 * Get corresponding match from firewall chain. 356 */ 357 @VisibleForTesting getMatchByFirewallChain(final int chain)358 public long getMatchByFirewallChain(final int chain) { 359 switch (chain) { 360 case FIREWALL_CHAIN_DOZABLE: 361 return DOZABLE_MATCH; 362 case FIREWALL_CHAIN_STANDBY: 363 return STANDBY_MATCH; 364 case FIREWALL_CHAIN_POWERSAVE: 365 return POWERSAVE_MATCH; 366 case FIREWALL_CHAIN_RESTRICTED: 367 return RESTRICTED_MATCH; 368 case FIREWALL_CHAIN_LOW_POWER_STANDBY: 369 return LOW_POWER_STANDBY_MATCH; 370 case FIREWALL_CHAIN_OEM_DENY_1: 371 return OEM_DENY_1_MATCH; 372 case FIREWALL_CHAIN_OEM_DENY_2: 373 return OEM_DENY_2_MATCH; 374 case FIREWALL_CHAIN_OEM_DENY_3: 375 return OEM_DENY_3_MATCH; 376 default: 377 throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain); 378 } 379 } 380 381 /** 382 * Get if the chain is allow list or not. 383 * 384 * ALLOWLIST means the firewall denies all by default, uids must be explicitly allowed 385 * DENYLIST means the firewall allows all by default, uids must be explicitly denyed 386 */ isFirewallAllowList(final int chain)387 public boolean isFirewallAllowList(final int chain) { 388 switch (chain) { 389 case FIREWALL_CHAIN_DOZABLE: 390 case FIREWALL_CHAIN_POWERSAVE: 391 case FIREWALL_CHAIN_RESTRICTED: 392 case FIREWALL_CHAIN_LOW_POWER_STANDBY: 393 return true; 394 case FIREWALL_CHAIN_STANDBY: 395 case FIREWALL_CHAIN_OEM_DENY_1: 396 case FIREWALL_CHAIN_OEM_DENY_2: 397 case FIREWALL_CHAIN_OEM_DENY_3: 398 return false; 399 default: 400 throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain); 401 } 402 } 403 maybeThrow(final int err, final String msg)404 private void maybeThrow(final int err, final String msg) { 405 if (err != 0) { 406 throw new ServiceSpecificException(err, msg + ": " + Os.strerror(err)); 407 } 408 } 409 throwIfPreT(final String msg)410 private void throwIfPreT(final String msg) { 411 if (PRE_T) { 412 throw new UnsupportedOperationException(msg); 413 } 414 } 415 removeRule(final int uid, final long match, final String caller)416 private void removeRule(final int uid, final long match, final String caller) { 417 try { 418 synchronized (sUidOwnerMap) { 419 final UidOwnerValue oldMatch = sUidOwnerMap.getValue(new S32(uid)); 420 421 if (oldMatch == null) { 422 throw new ServiceSpecificException(ENOENT, 423 "sUidOwnerMap does not have entry for uid: " + uid); 424 } 425 426 final UidOwnerValue newMatch = new UidOwnerValue( 427 (match == IIF_MATCH) ? 0 : oldMatch.iif, 428 oldMatch.rule & ~match 429 ); 430 431 if (newMatch.rule == 0) { 432 sUidOwnerMap.deleteEntry(new S32(uid)); 433 } else { 434 sUidOwnerMap.updateEntry(new S32(uid), newMatch); 435 } 436 } 437 } catch (ErrnoException e) { 438 throw new ServiceSpecificException(e.errno, 439 caller + " failed to remove rule: " + Os.strerror(e.errno)); 440 } 441 } 442 addRule(final int uid, final long match, final int iif, final String caller)443 private void addRule(final int uid, final long match, final int iif, final String caller) { 444 if (match != IIF_MATCH && iif != 0) { 445 throw new ServiceSpecificException(EINVAL, 446 "Non-interface match must have zero interface index"); 447 } 448 449 try { 450 synchronized (sUidOwnerMap) { 451 final UidOwnerValue oldMatch = sUidOwnerMap.getValue(new S32(uid)); 452 453 final UidOwnerValue newMatch; 454 if (oldMatch != null) { 455 newMatch = new UidOwnerValue( 456 (match == IIF_MATCH) ? iif : oldMatch.iif, 457 oldMatch.rule | match 458 ); 459 } else { 460 newMatch = new UidOwnerValue( 461 iif, 462 match 463 ); 464 } 465 sUidOwnerMap.updateEntry(new S32(uid), newMatch); 466 } 467 } catch (ErrnoException e) { 468 throw new ServiceSpecificException(e.errno, 469 caller + " failed to add rule: " + Os.strerror(e.errno)); 470 } 471 } 472 addRule(final int uid, final long match, final String caller)473 private void addRule(final int uid, final long match, final String caller) { 474 addRule(uid, match, 0 /* iif */, caller); 475 } 476 477 /** 478 * Add naughty app bandwidth rule for specific app 479 * 480 * @param uid uid of target app 481 * @throws ServiceSpecificException in case of failure, with an error code indicating the 482 * cause of the failure. 483 */ addNaughtyApp(final int uid)484 public void addNaughtyApp(final int uid) { 485 throwIfPreT("addNaughtyApp is not available on pre-T devices"); 486 487 if (sEnableJavaBpfMap) { 488 addRule(uid, PENALTY_BOX_MATCH, "addNaughtyApp"); 489 } else { 490 final int err = native_addNaughtyApp(uid); 491 maybeThrow(err, "Unable to add naughty app"); 492 } 493 } 494 495 /** 496 * Remove naughty app bandwidth rule for specific app 497 * 498 * @param uid uid of target app 499 * @throws ServiceSpecificException in case of failure, with an error code indicating the 500 * cause of the failure. 501 */ removeNaughtyApp(final int uid)502 public void removeNaughtyApp(final int uid) { 503 throwIfPreT("removeNaughtyApp is not available on pre-T devices"); 504 505 if (sEnableJavaBpfMap) { 506 removeRule(uid, PENALTY_BOX_MATCH, "removeNaughtyApp"); 507 } else { 508 final int err = native_removeNaughtyApp(uid); 509 maybeThrow(err, "Unable to remove naughty app"); 510 } 511 } 512 513 /** 514 * Add nice app bandwidth rule for specific app 515 * 516 * @param uid uid of target app 517 * @throws ServiceSpecificException in case of failure, with an error code indicating the 518 * cause of the failure. 519 */ addNiceApp(final int uid)520 public void addNiceApp(final int uid) { 521 throwIfPreT("addNiceApp is not available on pre-T devices"); 522 523 if (sEnableJavaBpfMap) { 524 addRule(uid, HAPPY_BOX_MATCH, "addNiceApp"); 525 } else { 526 final int err = native_addNiceApp(uid); 527 maybeThrow(err, "Unable to add nice app"); 528 } 529 } 530 531 /** 532 * Remove nice app bandwidth rule for specific app 533 * 534 * @param uid uid of target app 535 * @throws ServiceSpecificException in case of failure, with an error code indicating the 536 * cause of the failure. 537 */ removeNiceApp(final int uid)538 public void removeNiceApp(final int uid) { 539 throwIfPreT("removeNiceApp is not available on pre-T devices"); 540 541 if (sEnableJavaBpfMap) { 542 removeRule(uid, HAPPY_BOX_MATCH, "removeNiceApp"); 543 } else { 544 final int err = native_removeNiceApp(uid); 545 maybeThrow(err, "Unable to remove nice app"); 546 } 547 } 548 549 /** 550 * Set target firewall child chain 551 * 552 * @param childChain target chain to enable 553 * @param enable whether to enable or disable child chain. 554 * @throws UnsupportedOperationException if called on pre-T devices. 555 * @throws ServiceSpecificException in case of failure, with an error code indicating the 556 * cause of the failure. 557 */ setChildChain(final int childChain, final boolean enable)558 public void setChildChain(final int childChain, final boolean enable) { 559 throwIfPreT("setChildChain is not available on pre-T devices"); 560 561 if (sEnableJavaBpfMap) { 562 final long match = getMatchByFirewallChain(childChain); 563 try { 564 synchronized (sUidRulesConfigBpfMapLock) { 565 final U32 config = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY); 566 final long newConfig = enable ? (config.val | match) : (config.val & ~match); 567 sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(newConfig)); 568 } 569 } catch (ErrnoException e) { 570 throw new ServiceSpecificException(e.errno, 571 "Unable to set child chain: " + Os.strerror(e.errno)); 572 } 573 } else { 574 final int err = native_setChildChain(childChain, enable); 575 maybeThrow(err, "Unable to set child chain"); 576 } 577 } 578 579 /** 580 * Get the specified firewall chain's status. 581 * 582 * @param childChain target chain 583 * @return {@code true} if chain is enabled, {@code false} if chain is not enabled. 584 * @throws UnsupportedOperationException if called on pre-T devices. 585 * @throws ServiceSpecificException in case of failure, with an error code indicating the 586 * cause of the failure. 587 */ isChainEnabled(final int childChain)588 public boolean isChainEnabled(final int childChain) { 589 throwIfPreT("isChainEnabled is not available on pre-T devices"); 590 591 final long match = getMatchByFirewallChain(childChain); 592 try { 593 final U32 config = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY); 594 return (config.val & match) != 0; 595 } catch (ErrnoException e) { 596 throw new ServiceSpecificException(e.errno, 597 "Unable to get firewall chain status: " + Os.strerror(e.errno)); 598 } 599 } 600 asSet(final int[] uids)601 private Set<Integer> asSet(final int[] uids) { 602 final Set<Integer> uidSet = new ArraySet<>(); 603 for (final int uid: uids) { 604 uidSet.add(uid); 605 } 606 return uidSet; 607 } 608 609 /** 610 * Replaces the contents of the specified UID-based firewall chain. 611 * Enables the chain for specified uids and disables the chain for non-specified uids. 612 * 613 * @param chain Target chain. 614 * @param uids The list of UIDs to allow/deny. 615 * @throws UnsupportedOperationException if called on pre-T devices. 616 * @throws IllegalArgumentException if {@code chain} is not a valid chain. 617 */ replaceUidChain(final int chain, final int[] uids)618 public void replaceUidChain(final int chain, final int[] uids) { 619 throwIfPreT("replaceUidChain is not available on pre-T devices"); 620 621 if (sEnableJavaBpfMap) { 622 final long match; 623 try { 624 match = getMatchByFirewallChain(chain); 625 } catch (ServiceSpecificException e) { 626 // Throws IllegalArgumentException to keep the behavior of 627 // ConnectivityManager#replaceFirewallChain API 628 throw new IllegalArgumentException("Invalid firewall chain: " + chain); 629 } 630 final Set<Integer> uidSet = asSet(uids); 631 final Set<Integer> uidSetToRemoveRule = new ArraySet<>(); 632 try { 633 synchronized (sUidOwnerMap) { 634 sUidOwnerMap.forEach((uid, config) -> { 635 // config could be null if there is a concurrent entry deletion. 636 // http://b/220084230. But sUidOwnerMap update must be done while holding a 637 // lock, so this should not happen. 638 if (config == null) { 639 Log.wtf(TAG, "sUidOwnerMap entry was deleted while holding a lock"); 640 } else if (!uidSet.contains((int) uid.val) && (config.rule & match) != 0) { 641 uidSetToRemoveRule.add((int) uid.val); 642 } 643 }); 644 645 for (final int uid : uidSetToRemoveRule) { 646 removeRule(uid, match, "replaceUidChain"); 647 } 648 for (final int uid : uids) { 649 addRule(uid, match, "replaceUidChain"); 650 } 651 } 652 } catch (ErrnoException | ServiceSpecificException e) { 653 Log.e(TAG, "replaceUidChain failed: " + e); 654 } 655 } else { 656 final int err; 657 switch (chain) { 658 case FIREWALL_CHAIN_DOZABLE: 659 err = native_replaceUidChain("fw_dozable", true /* isAllowList */, uids); 660 break; 661 case FIREWALL_CHAIN_STANDBY: 662 err = native_replaceUidChain("fw_standby", false /* isAllowList */, uids); 663 break; 664 case FIREWALL_CHAIN_POWERSAVE: 665 err = native_replaceUidChain("fw_powersave", true /* isAllowList */, uids); 666 break; 667 case FIREWALL_CHAIN_RESTRICTED: 668 err = native_replaceUidChain("fw_restricted", true /* isAllowList */, uids); 669 break; 670 case FIREWALL_CHAIN_LOW_POWER_STANDBY: 671 err = native_replaceUidChain( 672 "fw_low_power_standby", true /* isAllowList */, uids); 673 break; 674 case FIREWALL_CHAIN_OEM_DENY_1: 675 err = native_replaceUidChain("fw_oem_deny_1", false /* isAllowList */, uids); 676 break; 677 case FIREWALL_CHAIN_OEM_DENY_2: 678 err = native_replaceUidChain("fw_oem_deny_2", false /* isAllowList */, uids); 679 break; 680 case FIREWALL_CHAIN_OEM_DENY_3: 681 err = native_replaceUidChain("fw_oem_deny_3", false /* isAllowList */, uids); 682 break; 683 default: 684 throw new IllegalArgumentException("replaceFirewallChain with invalid chain: " 685 + chain); 686 } 687 if (err != 0) { 688 Log.e(TAG, "replaceUidChain failed: " + Os.strerror(-err)); 689 } 690 } 691 } 692 693 /** 694 * Set firewall rule for uid 695 * 696 * @param childChain target chain 697 * @param uid uid to allow/deny 698 * @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY 699 * @throws ServiceSpecificException in case of failure, with an error code indicating the 700 * cause of the failure. 701 */ setUidRule(final int childChain, final int uid, final int firewallRule)702 public void setUidRule(final int childChain, final int uid, final int firewallRule) { 703 throwIfPreT("setUidRule is not available on pre-T devices"); 704 705 if (sEnableJavaBpfMap) { 706 final long match = getMatchByFirewallChain(childChain); 707 final boolean isAllowList = isFirewallAllowList(childChain); 708 final boolean add = (firewallRule == FIREWALL_RULE_ALLOW && isAllowList) 709 || (firewallRule == FIREWALL_RULE_DENY && !isAllowList); 710 711 if (add) { 712 addRule(uid, match, "setUidRule"); 713 } else { 714 removeRule(uid, match, "setUidRule"); 715 } 716 } else { 717 final int err = native_setUidRule(childChain, uid, firewallRule); 718 maybeThrow(err, "Unable to set uid rule"); 719 } 720 } 721 722 /** 723 * Get firewall rule of specified firewall chain on specified uid. 724 * 725 * @param childChain target chain 726 * @param uid target uid 727 * @return either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY 728 * @throws UnsupportedOperationException if called on pre-T devices. 729 * @throws ServiceSpecificException in case of failure, with an error code indicating the 730 * cause of the failure. 731 */ getUidRule(final int childChain, final int uid)732 public int getUidRule(final int childChain, final int uid) { 733 throwIfPreT("isUidChainEnabled is not available on pre-T devices"); 734 735 final long match = getMatchByFirewallChain(childChain); 736 final boolean isAllowList = isFirewallAllowList(childChain); 737 try { 738 final UidOwnerValue uidMatch = sUidOwnerMap.getValue(new S32(uid)); 739 final boolean isMatchEnabled = uidMatch != null && (uidMatch.rule & match) != 0; 740 return isMatchEnabled == isAllowList ? FIREWALL_RULE_ALLOW : FIREWALL_RULE_DENY; 741 } catch (ErrnoException e) { 742 throw new ServiceSpecificException(e.errno, 743 "Unable to get uid rule status: " + Os.strerror(e.errno)); 744 } 745 } 746 getUidsMatchEnabled(final int childChain)747 private Set<Integer> getUidsMatchEnabled(final int childChain) throws ErrnoException { 748 final long match = getMatchByFirewallChain(childChain); 749 Set<Integer> uids = new ArraySet<>(); 750 synchronized (sUidOwnerMap) { 751 sUidOwnerMap.forEach((uid, val) -> { 752 if (val == null) { 753 Log.wtf(TAG, "sUidOwnerMap entry was deleted while holding a lock"); 754 } else { 755 if ((val.rule & match) != 0) { 756 uids.add(uid.val); 757 } 758 } 759 }); 760 } 761 return uids; 762 } 763 764 /** 765 * Get uids that has FIREWALL_RULE_ALLOW on allowlist chain. 766 * Allowlist means the firewall denies all by default, uids must be explicitly allowed. 767 * 768 * Note that uids that has FIREWALL_RULE_DENY on allowlist chain can not be computed from the 769 * bpf map, since all the uids that does not have explicit FIREWALL_RULE_ALLOW rule in bpf map 770 * are determined to have FIREWALL_RULE_DENY. 771 * 772 * @param childChain target chain 773 * @return Set of uids 774 */ getUidsWithAllowRuleOnAllowListChain(final int childChain)775 public Set<Integer> getUidsWithAllowRuleOnAllowListChain(final int childChain) 776 throws ErrnoException { 777 if (!isFirewallAllowList(childChain)) { 778 throw new IllegalArgumentException("getUidsWithAllowRuleOnAllowListChain is called with" 779 + " denylist chain:" + childChain); 780 } 781 // Corresponding match is enabled for uids that has FIREWALL_RULE_ALLOW on allowlist chain. 782 return getUidsMatchEnabled(childChain); 783 } 784 785 /** 786 * Get uids that has FIREWALL_RULE_DENY on denylist chain. 787 * Denylist means the firewall allows all by default, uids must be explicitly denyed 788 * 789 * Note that uids that has FIREWALL_RULE_ALLOW on denylist chain can not be computed from the 790 * bpf map, since all the uids that does not have explicit FIREWALL_RULE_DENY rule in bpf map 791 * are determined to have the FIREWALL_RULE_ALLOW. 792 * 793 * @param childChain target chain 794 * @return Set of uids 795 */ getUidsWithDenyRuleOnDenyListChain(final int childChain)796 public Set<Integer> getUidsWithDenyRuleOnDenyListChain(final int childChain) 797 throws ErrnoException { 798 if (isFirewallAllowList(childChain)) { 799 throw new IllegalArgumentException("getUidsWithDenyRuleOnDenyListChain is called with" 800 + " allowlist chain:" + childChain); 801 } 802 // Corresponding match is enabled for uids that has FIREWALL_RULE_DENY on denylist chain. 803 return getUidsMatchEnabled(childChain); 804 } 805 806 /** 807 * Add ingress interface filtering rules to a list of UIDs 808 * 809 * For a given uid, once a filtering rule is added, the kernel will only allow packets from the 810 * allowed interface and loopback to be sent to the list of UIDs. 811 * 812 * Calling this method on one or more UIDs with an existing filtering rule but a different 813 * interface name will result in the filtering rule being updated to allow the new interface 814 * instead. Otherwise calling this method will not affect existing rules set on other UIDs. 815 * 816 * @param ifName the name of the interface on which the filtering rules will allow packets to 817 * be received. 818 * @param uids an array of UIDs which the filtering rules will be set 819 * @throws RemoteException when netd has crashed. 820 * @throws ServiceSpecificException in case of failure, with an error code indicating the 821 * cause of the failure. 822 */ addUidInterfaceRules(final String ifName, final int[] uids)823 public void addUidInterfaceRules(final String ifName, final int[] uids) throws RemoteException { 824 if (PRE_T) { 825 mNetd.firewallAddUidInterfaceRules(ifName, uids); 826 return; 827 } 828 829 if (sEnableJavaBpfMap) { 830 // Null ifName is a wildcard to allow apps to receive packets on all interfaces and 831 // ifIndex is set to 0. 832 final int ifIndex; 833 if (ifName == null) { 834 ifIndex = 0; 835 } else { 836 ifIndex = mDeps.getIfIndex(ifName); 837 if (ifIndex == 0) { 838 throw new ServiceSpecificException(ENODEV, 839 "Failed to get index of interface " + ifName); 840 } 841 } 842 for (final int uid : uids) { 843 try { 844 addRule(uid, IIF_MATCH, ifIndex, "addUidInterfaceRules"); 845 } catch (ServiceSpecificException e) { 846 Log.e(TAG, "addRule failed uid=" + uid + " ifName=" + ifName + ", " + e); 847 } 848 } 849 } else { 850 final int err = native_addUidInterfaceRules(ifName, uids); 851 maybeThrow(err, "Unable to add uid interface rules"); 852 } 853 } 854 855 /** 856 * Remove ingress interface filtering rules from a list of UIDs 857 * 858 * Clear the ingress interface filtering rules from the list of UIDs which were previously set 859 * by addUidInterfaceRules(). Ignore any uid which does not have filtering rule. 860 * 861 * @param uids an array of UIDs from which the filtering rules will be removed 862 * @throws RemoteException when netd has crashed. 863 * @throws ServiceSpecificException in case of failure, with an error code indicating the 864 * cause of the failure. 865 */ removeUidInterfaceRules(final int[] uids)866 public void removeUidInterfaceRules(final int[] uids) throws RemoteException { 867 if (PRE_T) { 868 mNetd.firewallRemoveUidInterfaceRules(uids); 869 return; 870 } 871 872 if (sEnableJavaBpfMap) { 873 for (final int uid : uids) { 874 try { 875 removeRule(uid, IIF_MATCH, "removeUidInterfaceRules"); 876 } catch (ServiceSpecificException e) { 877 Log.e(TAG, "removeRule failed uid=" + uid + ", " + e); 878 } 879 } 880 } else { 881 final int err = native_removeUidInterfaceRules(uids); 882 maybeThrow(err, "Unable to remove uid interface rules"); 883 } 884 } 885 886 /** 887 * Update lockdown rule for uid 888 * 889 * @param uid target uid to add/remove the rule 890 * @param add {@code true} to add the rule, {@code false} to remove the rule. 891 * @throws ServiceSpecificException in case of failure, with an error code indicating the 892 * cause of the failure. 893 */ updateUidLockdownRule(final int uid, final boolean add)894 public void updateUidLockdownRule(final int uid, final boolean add) { 895 throwIfPreT("updateUidLockdownRule is not available on pre-T devices"); 896 897 if (sEnableJavaBpfMap) { 898 if (add) { 899 addRule(uid, LOCKDOWN_VPN_MATCH, "updateUidLockdownRule"); 900 } else { 901 removeRule(uid, LOCKDOWN_VPN_MATCH, "updateUidLockdownRule"); 902 } 903 } else { 904 final int err = native_updateUidLockdownRule(uid, add); 905 maybeThrow(err, "Unable to update lockdown rule"); 906 } 907 } 908 909 /** 910 * Request netd to change the current active network stats map. 911 * 912 * @throws UnsupportedOperationException if called on pre-T devices. 913 * @throws ServiceSpecificException in case of failure, with an error code indicating the 914 * cause of the failure. 915 */ swapActiveStatsMap()916 public void swapActiveStatsMap() { 917 throwIfPreT("swapActiveStatsMap is not available on pre-T devices"); 918 919 if (sEnableJavaBpfMap) { 920 try { 921 synchronized (sCurrentStatsMapConfigLock) { 922 final long config = sConfigurationMap.getValue( 923 CURRENT_STATS_MAP_CONFIGURATION_KEY).val; 924 final long newConfig = (config == STATS_SELECT_MAP_A) 925 ? STATS_SELECT_MAP_B : STATS_SELECT_MAP_A; 926 sConfigurationMap.updateEntry(CURRENT_STATS_MAP_CONFIGURATION_KEY, 927 new U32(newConfig)); 928 } 929 } catch (ErrnoException e) { 930 throw new ServiceSpecificException(e.errno, "Failed to swap active stats map"); 931 } 932 933 // After changing the config, it's needed to make sure all the current running eBPF 934 // programs are finished and all the CPUs are aware of this config change before the old 935 // map is modified. So special hack is needed here to wait for the kernel to do a 936 // synchronize_rcu(). Once the kernel called synchronize_rcu(), the updated config will 937 // be available to all cores and the next eBPF programs triggered inside the kernel will 938 // use the new map configuration. So once this function returns it is safe to modify the 939 // old stats map without concerning about race between the kernel and userspace. 940 final int err = mDeps.synchronizeKernelRCU(); 941 maybeThrow(err, "synchronizeKernelRCU failed"); 942 } else { 943 final int err = native_swapActiveStatsMap(); 944 maybeThrow(err, "Unable to swap active stats map"); 945 } 946 } 947 948 /** 949 * Assigns android.permission.INTERNET and/or android.permission.UPDATE_DEVICE_STATS to the uids 950 * specified. Or remove all permissions from the uids. 951 * 952 * @param permissions The permission to grant, it could be either PERMISSION_INTERNET and/or 953 * PERMISSION_UPDATE_DEVICE_STATS. If the permission is NO_PERMISSIONS, then 954 * revoke all permissions for the uids. 955 * @param uids uid of users to grant permission 956 * @throws RemoteException when netd has crashed. 957 */ setNetPermForUids(final int permissions, final int[] uids)958 public void setNetPermForUids(final int permissions, final int[] uids) throws RemoteException { 959 if (PRE_T) { 960 mNetd.trafficSetNetPermForUids(permissions, uids); 961 return; 962 } 963 964 if (sEnableJavaBpfMap) { 965 // Remove the entry if package is uninstalled or uid has only INTERNET permission. 966 if (permissions == PERMISSION_UNINSTALLED || permissions == PERMISSION_INTERNET) { 967 for (final int uid : uids) { 968 try { 969 sUidPermissionMap.deleteEntry(new S32(uid)); 970 } catch (ErrnoException e) { 971 Log.e(TAG, "Failed to remove uid " + uid + " from permission map: " + e); 972 } 973 } 974 return; 975 } 976 977 for (final int uid : uids) { 978 try { 979 sUidPermissionMap.updateEntry(new S32(uid), new U8((short) permissions)); 980 } catch (ErrnoException e) { 981 Log.e(TAG, "Failed to set permission " 982 + permissions + " to uid " + uid + ": " + e); 983 } 984 } 985 } else { 986 native_setPermissionForUids(permissions, uids); 987 } 988 } 989 990 /** Register callback for statsd to pull atom. */ setPullAtomCallback(final Context context)991 public void setPullAtomCallback(final Context context) { 992 throwIfPreT("setPullAtomCallback is not available on pre-T devices"); 993 994 final StatsManager statsManager = context.getSystemService(StatsManager.class); 995 statsManager.setPullAtomCallback(NETWORK_BPF_MAP_INFO, null /* metadata */, 996 BackgroundThread.getExecutor(), this::pullBpfMapInfoAtom); 997 } 998 getMapSize(IBpfMap<K, V> map)999 private <K extends Struct, V extends Struct> int getMapSize(IBpfMap<K, V> map) 1000 throws ErrnoException { 1001 // forEach could restart iteration from the beginning if there is a concurrent entry 1002 // deletion. netd and skDestroyListener could delete CookieTagMap entry concurrently. 1003 // So using Set to count the number of entry in the map. 1004 Set<K> keySet = new ArraySet<>(); 1005 map.forEach((k, v) -> keySet.add(k)); 1006 return keySet.size(); 1007 } 1008 1009 /** Callback for StatsManager#setPullAtomCallback */ 1010 @VisibleForTesting pullBpfMapInfoAtom(final int atomTag, final List<StatsEvent> data)1011 public int pullBpfMapInfoAtom(final int atomTag, final List<StatsEvent> data) { 1012 if (atomTag != NETWORK_BPF_MAP_INFO) { 1013 Log.e(TAG, "Unexpected atom tag: " + atomTag); 1014 return StatsManager.PULL_SKIP; 1015 } 1016 1017 try { 1018 data.add(mDeps.buildStatsEvent(getMapSize(sCookieTagMap), getMapSize(sUidOwnerMap), 1019 getMapSize(sUidPermissionMap))); 1020 } catch (ErrnoException e) { 1021 Log.e(TAG, "Failed to pull NETWORK_BPF_MAP_INFO atom: " + e); 1022 return StatsManager.PULL_SKIP; 1023 } 1024 return StatsManager.PULL_SUCCESS; 1025 } 1026 permissionToString(int permissionMask)1027 private String permissionToString(int permissionMask) { 1028 if (permissionMask == PERMISSION_NONE) { 1029 return "PERMISSION_NONE"; 1030 } 1031 if (permissionMask == PERMISSION_UNINSTALLED) { 1032 // PERMISSION_UNINSTALLED should never appear in the map 1033 return "PERMISSION_UNINSTALLED error!"; 1034 } 1035 1036 final StringJoiner sj = new StringJoiner(" "); 1037 for (Pair<Integer, String> permission: PERMISSION_LIST) { 1038 final int permissionFlag = permission.first; 1039 final String permissionName = permission.second; 1040 if ((permissionMask & permissionFlag) != 0) { 1041 sj.add(permissionName); 1042 permissionMask &= ~permissionFlag; 1043 } 1044 } 1045 if (permissionMask != 0) { 1046 sj.add("PERMISSION_UNKNOWN(" + permissionMask + ")"); 1047 } 1048 return sj.toString(); 1049 } 1050 matchToString(long matchMask)1051 private String matchToString(long matchMask) { 1052 if (matchMask == NO_MATCH) { 1053 return "NO_MATCH"; 1054 } 1055 1056 final StringJoiner sj = new StringJoiner(" "); 1057 for (Pair<Long, String> match: MATCH_LIST) { 1058 final long matchFlag = match.first; 1059 final String matchName = match.second; 1060 if ((matchMask & matchFlag) != 0) { 1061 sj.add(matchName); 1062 matchMask &= ~matchFlag; 1063 } 1064 } 1065 if (matchMask != 0) { 1066 sj.add("UNKNOWN_MATCH(" + matchMask + ")"); 1067 } 1068 return sj.toString(); 1069 } 1070 dumpOwnerMatchConfig(final IndentingPrintWriter pw)1071 private void dumpOwnerMatchConfig(final IndentingPrintWriter pw) { 1072 try { 1073 final long match = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val; 1074 pw.println("current ownerMatch configuration: " + match + " " + matchToString(match)); 1075 } catch (ErrnoException e) { 1076 pw.println("Failed to read ownerMatch configuration: " + e); 1077 } 1078 } 1079 dumpCurrentStatsMapConfig(final IndentingPrintWriter pw)1080 private void dumpCurrentStatsMapConfig(final IndentingPrintWriter pw) { 1081 try { 1082 final long config = sConfigurationMap.getValue(CURRENT_STATS_MAP_CONFIGURATION_KEY).val; 1083 final String currentStatsMap = 1084 (config == STATS_SELECT_MAP_A) ? "SELECT_MAP_A" : "SELECT_MAP_B"; 1085 pw.println("current statsMap configuration: " + config + " " + currentStatsMap); 1086 } catch (ErrnoException e) { 1087 pw.println("Falied to read current statsMap configuration: " + e); 1088 } 1089 } 1090 1091 /** 1092 * Dump BPF maps 1093 * 1094 * @param pw print writer 1095 * @param fd file descriptor to output 1096 * @param verbose verbose dump flag, if true dump the BpfMap contents 1097 * @throws IOException when file descriptor is invalid. 1098 * @throws ServiceSpecificException when the method is called on an unsupported device. 1099 */ dump(final IndentingPrintWriter pw, final FileDescriptor fd, boolean verbose)1100 public void dump(final IndentingPrintWriter pw, final FileDescriptor fd, boolean verbose) 1101 throws IOException, ServiceSpecificException { 1102 if (PRE_T) { 1103 throw new ServiceSpecificException( 1104 EOPNOTSUPP, "dumpsys connectivity trafficcontroller dump not available on pre-T" 1105 + " devices, use dumpsys netd trafficcontroller instead."); 1106 } 1107 mDeps.nativeDump(fd, verbose); 1108 1109 pw.println(); 1110 pw.println("sEnableJavaBpfMap: " + sEnableJavaBpfMap); 1111 if (verbose) { 1112 pw.println(); 1113 pw.println("BPF map content:"); 1114 pw.increaseIndent(); 1115 1116 dumpOwnerMatchConfig(pw); 1117 dumpCurrentStatsMapConfig(pw); 1118 pw.println(); 1119 1120 // TODO: Remove CookieTagMap content dump 1121 // NetworkStatsService also dumps CookieTagMap and NetworkStatsService is a right place 1122 // to dump CookieTagMap. But the TagSocketTest in CTS depends on this dump so the tests 1123 // need to be updated before remove the dump from BpfNetMaps. 1124 BpfDump.dumpMap(sCookieTagMap, pw, "sCookieTagMap", 1125 (key, value) -> "cookie=" + key.socketCookie 1126 + " tag=0x" + Long.toHexString(value.tag) 1127 + " uid=" + value.uid); 1128 BpfDump.dumpMap(sUidOwnerMap, pw, "sUidOwnerMap", 1129 (uid, match) -> { 1130 if ((match.rule & IIF_MATCH) != 0) { 1131 // TODO: convert interface index to interface name by IfaceIndexNameMap 1132 return uid.val + " " + matchToString(match.rule) + " " + match.iif; 1133 } else { 1134 return uid.val + " " + matchToString(match.rule); 1135 } 1136 }); 1137 BpfDump.dumpMap(sUidPermissionMap, pw, "sUidPermissionMap", 1138 (uid, permission) -> uid.val + " " + permissionToString(permission.val)); 1139 pw.decreaseIndent(); 1140 } 1141 } 1142 native_init(boolean startSkDestroyListener)1143 private static native void native_init(boolean startSkDestroyListener); native_addNaughtyApp(int uid)1144 private native int native_addNaughtyApp(int uid); native_removeNaughtyApp(int uid)1145 private native int native_removeNaughtyApp(int uid); native_addNiceApp(int uid)1146 private native int native_addNiceApp(int uid); native_removeNiceApp(int uid)1147 private native int native_removeNiceApp(int uid); native_setChildChain(int childChain, boolean enable)1148 private native int native_setChildChain(int childChain, boolean enable); native_replaceUidChain(String name, boolean isAllowlist, int[] uids)1149 private native int native_replaceUidChain(String name, boolean isAllowlist, int[] uids); native_setUidRule(int childChain, int uid, int firewallRule)1150 private native int native_setUidRule(int childChain, int uid, int firewallRule); native_addUidInterfaceRules(String ifName, int[] uids)1151 private native int native_addUidInterfaceRules(String ifName, int[] uids); native_removeUidInterfaceRules(int[] uids)1152 private native int native_removeUidInterfaceRules(int[] uids); native_updateUidLockdownRule(int uid, boolean add)1153 private native int native_updateUidLockdownRule(int uid, boolean add); native_swapActiveStatsMap()1154 private native int native_swapActiveStatsMap(); native_setPermissionForUids(int permissions, int[] uids)1155 private native void native_setPermissionForUids(int permissions, int[] uids); native_dump(FileDescriptor fd, boolean verbose)1156 private static native void native_dump(FileDescriptor fd, boolean verbose); native_synchronizeKernelRCU()1157 private static native int native_synchronizeKernelRCU(); 1158 } 1159