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.EPERM; 35 36 import static com.android.server.BpfNetMaps.DOZABLE_MATCH; 37 import static com.android.server.BpfNetMaps.HAPPY_BOX_MATCH; 38 import static com.android.server.BpfNetMaps.IIF_MATCH; 39 import static com.android.server.BpfNetMaps.LOCKDOWN_VPN_MATCH; 40 import static com.android.server.BpfNetMaps.LOW_POWER_STANDBY_MATCH; 41 import static com.android.server.BpfNetMaps.NO_MATCH; 42 import static com.android.server.BpfNetMaps.OEM_DENY_1_MATCH; 43 import static com.android.server.BpfNetMaps.OEM_DENY_2_MATCH; 44 import static com.android.server.BpfNetMaps.OEM_DENY_3_MATCH; 45 import static com.android.server.BpfNetMaps.PENALTY_BOX_MATCH; 46 import static com.android.server.BpfNetMaps.POWERSAVE_MATCH; 47 import static com.android.server.BpfNetMaps.RESTRICTED_MATCH; 48 import static com.android.server.BpfNetMaps.STANDBY_MATCH; 49 import static com.android.server.ConnectivityStatsLog.NETWORK_BPF_MAP_INFO; 50 51 import static org.junit.Assert.assertEquals; 52 import static org.junit.Assert.assertFalse; 53 import static org.junit.Assert.assertNull; 54 import static org.junit.Assert.assertThrows; 55 import static org.junit.Assert.assertTrue; 56 import static org.junit.Assume.assumeFalse; 57 import static org.mockito.Mockito.any; 58 import static org.mockito.Mockito.doReturn; 59 import static org.mockito.Mockito.doThrow; 60 import static org.mockito.Mockito.spy; 61 import static org.mockito.Mockito.verify; 62 63 import android.app.StatsManager; 64 import android.content.Context; 65 import android.net.INetd; 66 import android.os.Build; 67 import android.os.ServiceSpecificException; 68 import android.system.ErrnoException; 69 import android.util.ArraySet; 70 import android.util.IndentingPrintWriter; 71 72 import androidx.test.filters.SmallTest; 73 74 import com.android.modules.utils.build.SdkLevel; 75 import com.android.net.module.util.IBpfMap; 76 import com.android.net.module.util.Struct.S32; 77 import com.android.net.module.util.Struct.U32; 78 import com.android.net.module.util.Struct.U8; 79 import com.android.net.module.util.bpf.CookieTagMapKey; 80 import com.android.net.module.util.bpf.CookieTagMapValue; 81 import com.android.testutils.DevSdkIgnoreRule; 82 import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter; 83 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; 84 import com.android.testutils.DevSdkIgnoreRunner; 85 import com.android.testutils.TestBpfMap; 86 87 import org.junit.Before; 88 import org.junit.Rule; 89 import org.junit.Test; 90 import org.junit.runner.RunWith; 91 import org.mockito.Mock; 92 import org.mockito.MockitoAnnotations; 93 94 import java.io.FileDescriptor; 95 import java.io.StringWriter; 96 import java.util.ArrayList; 97 import java.util.List; 98 99 @RunWith(DevSdkIgnoreRunner.class) 100 @SmallTest 101 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) 102 public final class BpfNetMapsTest { 103 private static final String TAG = "BpfNetMapsTest"; 104 105 @Rule 106 public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(); 107 108 private static final int TEST_UID = 10086; 109 private static final int[] TEST_UIDS = {10002, 10003}; 110 private static final String TEST_IF_NAME = "wlan0"; 111 private static final int TEST_IF_INDEX = 7; 112 private static final int NO_IIF = 0; 113 private static final int NULL_IIF = 0; 114 private static final String CHAINNAME = "fw_dozable"; 115 private static final S32 UID_RULES_CONFIGURATION_KEY = new S32(0); 116 private static final S32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new S32(1); 117 private static final List<Integer> FIREWALL_CHAINS = List.of( 118 FIREWALL_CHAIN_DOZABLE, 119 FIREWALL_CHAIN_STANDBY, 120 FIREWALL_CHAIN_POWERSAVE, 121 FIREWALL_CHAIN_RESTRICTED, 122 FIREWALL_CHAIN_LOW_POWER_STANDBY, 123 FIREWALL_CHAIN_OEM_DENY_1, 124 FIREWALL_CHAIN_OEM_DENY_2, 125 FIREWALL_CHAIN_OEM_DENY_3 126 ); 127 128 private static final long STATS_SELECT_MAP_A = 0; 129 private static final long STATS_SELECT_MAP_B = 1; 130 131 private BpfNetMaps mBpfNetMaps; 132 133 @Mock INetd mNetd; 134 @Mock BpfNetMaps.Dependencies mDeps; 135 @Mock Context mContext; 136 private final IBpfMap<S32, U32> mConfigurationMap = new TestBpfMap<>(S32.class, U32.class); 137 private final IBpfMap<S32, UidOwnerValue> mUidOwnerMap = 138 new TestBpfMap<>(S32.class, UidOwnerValue.class); 139 private final IBpfMap<S32, U8> mUidPermissionMap = new TestBpfMap<>(S32.class, U8.class); 140 private final IBpfMap<CookieTagMapKey, CookieTagMapValue> mCookieTagMap = 141 spy(new TestBpfMap<>(CookieTagMapKey.class, CookieTagMapValue.class)); 142 143 @Before setUp()144 public void setUp() throws Exception { 145 MockitoAnnotations.initMocks(this); 146 doReturn(TEST_IF_INDEX).when(mDeps).getIfIndex(TEST_IF_NAME); 147 doReturn(0).when(mDeps).synchronizeKernelRCU(); 148 BpfNetMaps.setEnableJavaBpfMapForTest(true /* enable */); 149 BpfNetMaps.setConfigurationMapForTest(mConfigurationMap); 150 mConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(0)); 151 mConfigurationMap.updateEntry( 152 CURRENT_STATS_MAP_CONFIGURATION_KEY, new U32(STATS_SELECT_MAP_A)); 153 BpfNetMaps.setUidOwnerMapForTest(mUidOwnerMap); 154 BpfNetMaps.setUidPermissionMapForTest(mUidPermissionMap); 155 BpfNetMaps.setCookieTagMapForTest(mCookieTagMap); 156 mBpfNetMaps = new BpfNetMaps(mContext, mNetd, mDeps); 157 } 158 159 @Test testBpfNetMapsBeforeT()160 public void testBpfNetMapsBeforeT() throws Exception { 161 assumeFalse(SdkLevel.isAtLeastT()); 162 mBpfNetMaps.addUidInterfaceRules(TEST_IF_NAME, TEST_UIDS); 163 verify(mNetd).firewallAddUidInterfaceRules(TEST_IF_NAME, TEST_UIDS); 164 mBpfNetMaps.removeUidInterfaceRules(TEST_UIDS); 165 verify(mNetd).firewallRemoveUidInterfaceRules(TEST_UIDS); 166 mBpfNetMaps.setNetPermForUids(PERMISSION_INTERNET, TEST_UIDS); 167 verify(mNetd).trafficSetNetPermForUids(PERMISSION_INTERNET, TEST_UIDS); 168 } 169 getMatch(final List<Integer> chains)170 private long getMatch(final List<Integer> chains) { 171 long match = 0; 172 for (final int chain: chains) { 173 match |= mBpfNetMaps.getMatchByFirewallChain(chain); 174 } 175 return match; 176 } 177 doTestIsChainEnabled(final List<Integer> enableChains)178 private void doTestIsChainEnabled(final List<Integer> enableChains) throws Exception { 179 mConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(getMatch(enableChains))); 180 181 for (final int chain: FIREWALL_CHAINS) { 182 final String testCase = "EnabledChains: " + enableChains + " CheckedChain: " + chain; 183 if (enableChains.contains(chain)) { 184 assertTrue("Expected isChainEnabled returns True, " + testCase, 185 mBpfNetMaps.isChainEnabled(chain)); 186 } else { 187 assertFalse("Expected isChainEnabled returns False, " + testCase, 188 mBpfNetMaps.isChainEnabled(chain)); 189 } 190 } 191 } 192 doTestIsChainEnabled(final int enableChain)193 private void doTestIsChainEnabled(final int enableChain) throws Exception { 194 doTestIsChainEnabled(List.of(enableChain)); 195 } 196 197 @Test 198 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testIsChainEnabled()199 public void testIsChainEnabled() throws Exception { 200 doTestIsChainEnabled(FIREWALL_CHAIN_DOZABLE); 201 doTestIsChainEnabled(FIREWALL_CHAIN_STANDBY); 202 doTestIsChainEnabled(FIREWALL_CHAIN_POWERSAVE); 203 doTestIsChainEnabled(FIREWALL_CHAIN_RESTRICTED); 204 doTestIsChainEnabled(FIREWALL_CHAIN_LOW_POWER_STANDBY); 205 doTestIsChainEnabled(FIREWALL_CHAIN_OEM_DENY_1); 206 doTestIsChainEnabled(FIREWALL_CHAIN_OEM_DENY_2); 207 doTestIsChainEnabled(FIREWALL_CHAIN_OEM_DENY_3); 208 } 209 210 @Test 211 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testIsChainEnabledMultipleChainEnabled()212 public void testIsChainEnabledMultipleChainEnabled() throws Exception { 213 doTestIsChainEnabled(List.of( 214 FIREWALL_CHAIN_DOZABLE, 215 FIREWALL_CHAIN_STANDBY)); 216 doTestIsChainEnabled(List.of( 217 FIREWALL_CHAIN_DOZABLE, 218 FIREWALL_CHAIN_STANDBY, 219 FIREWALL_CHAIN_POWERSAVE, 220 FIREWALL_CHAIN_RESTRICTED)); 221 doTestIsChainEnabled(FIREWALL_CHAINS); 222 } 223 224 @Test 225 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testIsChainEnabledInvalidChain()226 public void testIsChainEnabledInvalidChain() { 227 final Class<ServiceSpecificException> expected = ServiceSpecificException.class; 228 assertThrows(expected, () -> mBpfNetMaps.isChainEnabled(-1 /* childChain */)); 229 assertThrows(expected, () -> mBpfNetMaps.isChainEnabled(1000 /* childChain */)); 230 } 231 232 @Test 233 @IgnoreAfter(Build.VERSION_CODES.S_V2) testIsChainEnabledBeforeT()234 public void testIsChainEnabledBeforeT() { 235 assertThrows(UnsupportedOperationException.class, 236 () -> mBpfNetMaps.isChainEnabled(FIREWALL_CHAIN_DOZABLE)); 237 } 238 doTestSetChildChain(final List<Integer> testChains)239 private void doTestSetChildChain(final List<Integer> testChains) throws Exception { 240 long expectedMatch = 0; 241 for (final int chain: testChains) { 242 expectedMatch |= mBpfNetMaps.getMatchByFirewallChain(chain); 243 } 244 245 assertEquals(0, mConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val); 246 247 for (final int chain: testChains) { 248 mBpfNetMaps.setChildChain(chain, true /* enable */); 249 } 250 assertEquals(expectedMatch, mConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val); 251 252 for (final int chain: testChains) { 253 mBpfNetMaps.setChildChain(chain, false /* enable */); 254 } 255 assertEquals(0, mConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val); 256 } 257 doTestSetChildChain(final int testChain)258 private void doTestSetChildChain(final int testChain) throws Exception { 259 doTestSetChildChain(List.of(testChain)); 260 } 261 262 @Test 263 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSetChildChain()264 public void testSetChildChain() throws Exception { 265 mConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(0)); 266 doTestSetChildChain(FIREWALL_CHAIN_DOZABLE); 267 doTestSetChildChain(FIREWALL_CHAIN_STANDBY); 268 doTestSetChildChain(FIREWALL_CHAIN_POWERSAVE); 269 doTestSetChildChain(FIREWALL_CHAIN_RESTRICTED); 270 doTestSetChildChain(FIREWALL_CHAIN_LOW_POWER_STANDBY); 271 doTestSetChildChain(FIREWALL_CHAIN_OEM_DENY_1); 272 doTestSetChildChain(FIREWALL_CHAIN_OEM_DENY_2); 273 doTestSetChildChain(FIREWALL_CHAIN_OEM_DENY_3); 274 } 275 276 @Test 277 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSetChildChainMultipleChain()278 public void testSetChildChainMultipleChain() throws Exception { 279 mConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(0)); 280 doTestSetChildChain(List.of( 281 FIREWALL_CHAIN_DOZABLE, 282 FIREWALL_CHAIN_STANDBY)); 283 doTestSetChildChain(List.of( 284 FIREWALL_CHAIN_DOZABLE, 285 FIREWALL_CHAIN_STANDBY, 286 FIREWALL_CHAIN_POWERSAVE, 287 FIREWALL_CHAIN_RESTRICTED)); 288 doTestSetChildChain(FIREWALL_CHAINS); 289 } 290 291 @Test 292 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSetChildChainInvalidChain()293 public void testSetChildChainInvalidChain() { 294 final Class<ServiceSpecificException> expected = ServiceSpecificException.class; 295 assertThrows(expected, 296 () -> mBpfNetMaps.setChildChain(-1 /* childChain */, true /* enable */)); 297 assertThrows(expected, 298 () -> mBpfNetMaps.setChildChain(1000 /* childChain */, true /* enable */)); 299 } 300 301 @Test 302 @IgnoreAfter(Build.VERSION_CODES.S_V2) testSetChildChainBeforeT()303 public void testSetChildChainBeforeT() { 304 assertThrows(UnsupportedOperationException.class, 305 () -> mBpfNetMaps.setChildChain(FIREWALL_CHAIN_DOZABLE, true /* enable */)); 306 } 307 checkUidOwnerValue(final int uid, final int expectedIif, final long expectedMatch)308 private void checkUidOwnerValue(final int uid, final int expectedIif, 309 final long expectedMatch) throws Exception { 310 final UidOwnerValue config = mUidOwnerMap.getValue(new S32(uid)); 311 if (expectedMatch == 0) { 312 assertNull(config); 313 } else { 314 assertEquals(expectedIif, config.iif); 315 assertEquals(expectedMatch, config.rule); 316 } 317 } 318 doTestRemoveNaughtyApp(final int iif, final long match)319 private void doTestRemoveNaughtyApp(final int iif, final long match) throws Exception { 320 mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match)); 321 322 mBpfNetMaps.removeNaughtyApp(TEST_UID); 323 324 checkUidOwnerValue(TEST_UID, iif, match & ~PENALTY_BOX_MATCH); 325 } 326 327 @Test 328 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testRemoveNaughtyApp()329 public void testRemoveNaughtyApp() throws Exception { 330 doTestRemoveNaughtyApp(NO_IIF, PENALTY_BOX_MATCH); 331 332 // PENALTY_BOX_MATCH with other matches 333 doTestRemoveNaughtyApp(NO_IIF, PENALTY_BOX_MATCH | DOZABLE_MATCH | POWERSAVE_MATCH); 334 335 // PENALTY_BOX_MATCH with IIF_MATCH 336 doTestRemoveNaughtyApp(TEST_IF_INDEX, PENALTY_BOX_MATCH | IIF_MATCH); 337 338 // PENALTY_BOX_MATCH is not enabled 339 doTestRemoveNaughtyApp(NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH); 340 } 341 342 @Test 343 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testRemoveNaughtyAppMissingUid()344 public void testRemoveNaughtyAppMissingUid() { 345 // UidOwnerMap does not have entry for TEST_UID 346 assertThrows(ServiceSpecificException.class, 347 () -> mBpfNetMaps.removeNaughtyApp(TEST_UID)); 348 } 349 350 @Test 351 @IgnoreAfter(Build.VERSION_CODES.S_V2) testRemoveNaughtyAppBeforeT()352 public void testRemoveNaughtyAppBeforeT() { 353 assertThrows(UnsupportedOperationException.class, 354 () -> mBpfNetMaps.removeNaughtyApp(TEST_UID)); 355 } 356 doTestAddNaughtyApp(final int iif, final long match)357 private void doTestAddNaughtyApp(final int iif, final long match) throws Exception { 358 if (match != NO_MATCH) { 359 mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match)); 360 } 361 362 mBpfNetMaps.addNaughtyApp(TEST_UID); 363 364 checkUidOwnerValue(TEST_UID, iif, match | PENALTY_BOX_MATCH); 365 } 366 367 @Test 368 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testAddNaughtyApp()369 public void testAddNaughtyApp() throws Exception { 370 doTestAddNaughtyApp(NO_IIF, NO_MATCH); 371 372 // Other matches are enabled 373 doTestAddNaughtyApp(NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH); 374 375 // IIF_MATCH is enabled 376 doTestAddNaughtyApp(TEST_IF_INDEX, IIF_MATCH); 377 378 // PENALTY_BOX_MATCH is already enabled 379 doTestAddNaughtyApp(NO_IIF, PENALTY_BOX_MATCH | DOZABLE_MATCH); 380 } 381 382 @Test 383 @IgnoreAfter(Build.VERSION_CODES.S_V2) testAddNaughtyAppBeforeT()384 public void testAddNaughtyAppBeforeT() { 385 assertThrows(UnsupportedOperationException.class, 386 () -> mBpfNetMaps.addNaughtyApp(TEST_UID)); 387 } 388 doTestRemoveNiceApp(final int iif, final long match)389 private void doTestRemoveNiceApp(final int iif, final long match) throws Exception { 390 mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match)); 391 392 mBpfNetMaps.removeNiceApp(TEST_UID); 393 394 checkUidOwnerValue(TEST_UID, iif, match & ~HAPPY_BOX_MATCH); 395 } 396 397 @Test 398 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testRemoveNiceApp()399 public void testRemoveNiceApp() throws Exception { 400 doTestRemoveNiceApp(NO_IIF, HAPPY_BOX_MATCH); 401 402 // HAPPY_BOX_MATCH with other matches 403 doTestRemoveNiceApp(NO_IIF, HAPPY_BOX_MATCH | DOZABLE_MATCH | POWERSAVE_MATCH); 404 405 // HAPPY_BOX_MATCH with IIF_MATCH 406 doTestRemoveNiceApp(TEST_IF_INDEX, HAPPY_BOX_MATCH | IIF_MATCH); 407 408 // HAPPY_BOX_MATCH is not enabled 409 doTestRemoveNiceApp(NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH); 410 } 411 412 @Test 413 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testRemoveNiceAppMissingUid()414 public void testRemoveNiceAppMissingUid() { 415 // UidOwnerMap does not have entry for TEST_UID 416 assertThrows(ServiceSpecificException.class, 417 () -> mBpfNetMaps.removeNiceApp(TEST_UID)); 418 } 419 420 @Test 421 @IgnoreAfter(Build.VERSION_CODES.S_V2) testRemoveNiceAppBeforeT()422 public void testRemoveNiceAppBeforeT() { 423 assertThrows(UnsupportedOperationException.class, 424 () -> mBpfNetMaps.removeNiceApp(TEST_UID)); 425 } 426 doTestAddNiceApp(final int iif, final long match)427 private void doTestAddNiceApp(final int iif, final long match) throws Exception { 428 if (match != NO_MATCH) { 429 mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match)); 430 } 431 432 mBpfNetMaps.addNiceApp(TEST_UID); 433 434 checkUidOwnerValue(TEST_UID, iif, match | HAPPY_BOX_MATCH); 435 } 436 437 @Test 438 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testAddNiceApp()439 public void testAddNiceApp() throws Exception { 440 doTestAddNiceApp(NO_IIF, NO_MATCH); 441 442 // Other matches are enabled 443 doTestAddNiceApp(NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH); 444 445 // IIF_MATCH is enabled 446 doTestAddNiceApp(TEST_IF_INDEX, IIF_MATCH); 447 448 // HAPPY_BOX_MATCH is already enabled 449 doTestAddNiceApp(NO_IIF, HAPPY_BOX_MATCH | DOZABLE_MATCH); 450 } 451 452 @Test 453 @IgnoreAfter(Build.VERSION_CODES.S_V2) testAddNiceAppBeforeT()454 public void testAddNiceAppBeforeT() { 455 assertThrows(UnsupportedOperationException.class, 456 () -> mBpfNetMaps.addNiceApp(TEST_UID)); 457 } 458 doTestUpdateUidLockdownRule(final int iif, final long match, final boolean add)459 private void doTestUpdateUidLockdownRule(final int iif, final long match, final boolean add) 460 throws Exception { 461 if (match != NO_MATCH) { 462 mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match)); 463 } 464 465 mBpfNetMaps.updateUidLockdownRule(TEST_UID, add); 466 467 final long expectedMatch = add ? match | LOCKDOWN_VPN_MATCH : match & ~LOCKDOWN_VPN_MATCH; 468 checkUidOwnerValue(TEST_UID, iif, expectedMatch); 469 } 470 471 private static final boolean ADD = true; 472 private static final boolean REMOVE = false; 473 474 @Test 475 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testUpdateUidLockdownRuleAddLockdown()476 public void testUpdateUidLockdownRuleAddLockdown() throws Exception { 477 doTestUpdateUidLockdownRule(NO_IIF, NO_MATCH, ADD); 478 479 // Other matches are enabled 480 doTestUpdateUidLockdownRule( 481 NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH, ADD); 482 483 // IIF_MATCH is enabled 484 doTestUpdateUidLockdownRule(TEST_IF_INDEX, DOZABLE_MATCH, ADD); 485 486 // LOCKDOWN_VPN_MATCH is already enabled 487 doTestUpdateUidLockdownRule(NO_IIF, LOCKDOWN_VPN_MATCH | DOZABLE_MATCH, ADD); 488 } 489 490 @Test 491 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testUpdateUidLockdownRuleRemoveLockdown()492 public void testUpdateUidLockdownRuleRemoveLockdown() throws Exception { 493 doTestUpdateUidLockdownRule(NO_IIF, LOCKDOWN_VPN_MATCH, REMOVE); 494 495 // LOCKDOWN_VPN_MATCH with other matches 496 doTestUpdateUidLockdownRule( 497 NO_IIF, LOCKDOWN_VPN_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH, REMOVE); 498 499 // LOCKDOWN_VPN_MATCH with IIF_MATCH 500 doTestUpdateUidLockdownRule(TEST_IF_INDEX, LOCKDOWN_VPN_MATCH | IIF_MATCH, REMOVE); 501 502 // LOCKDOWN_VPN_MATCH is not enabled 503 doTestUpdateUidLockdownRule(NO_IIF, POWERSAVE_MATCH | RESTRICTED_MATCH, REMOVE); 504 } 505 506 @Test 507 @IgnoreAfter(Build.VERSION_CODES.S_V2) testUpdateUidLockdownRuleBeforeT()508 public void testUpdateUidLockdownRuleBeforeT() { 509 assertThrows(UnsupportedOperationException.class, 510 () -> mBpfNetMaps.updateUidLockdownRule(TEST_UID, true /* add */)); 511 } 512 513 @Test 514 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testAddUidInterfaceRules()515 public void testAddUidInterfaceRules() throws Exception { 516 final int uid0 = TEST_UIDS[0]; 517 final int uid1 = TEST_UIDS[1]; 518 519 mBpfNetMaps.addUidInterfaceRules(TEST_IF_NAME, TEST_UIDS); 520 521 checkUidOwnerValue(uid0, TEST_IF_INDEX, IIF_MATCH); 522 checkUidOwnerValue(uid1, TEST_IF_INDEX, IIF_MATCH); 523 } 524 525 @Test 526 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testAddUidInterfaceRulesWithOtherMatch()527 public void testAddUidInterfaceRulesWithOtherMatch() throws Exception { 528 final int uid0 = TEST_UIDS[0]; 529 final int uid1 = TEST_UIDS[1]; 530 final long match0 = DOZABLE_MATCH; 531 final long match1 = DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH; 532 mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(NO_IIF, match0)); 533 mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(NO_IIF, match1)); 534 535 mBpfNetMaps.addUidInterfaceRules(TEST_IF_NAME, TEST_UIDS); 536 537 checkUidOwnerValue(uid0, TEST_IF_INDEX, match0 | IIF_MATCH); 538 checkUidOwnerValue(uid1, TEST_IF_INDEX, match1 | IIF_MATCH); 539 } 540 541 @Test 542 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testAddUidInterfaceRulesWithExistingIifMatch()543 public void testAddUidInterfaceRulesWithExistingIifMatch() throws Exception { 544 final int uid0 = TEST_UIDS[0]; 545 final int uid1 = TEST_UIDS[1]; 546 final long match0 = IIF_MATCH; 547 final long match1 = IIF_MATCH | DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH; 548 mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(TEST_IF_INDEX + 1, match0)); 549 mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(NULL_IIF, match1)); 550 551 mBpfNetMaps.addUidInterfaceRules(TEST_IF_NAME, TEST_UIDS); 552 553 checkUidOwnerValue(uid0, TEST_IF_INDEX, match0); 554 checkUidOwnerValue(uid1, TEST_IF_INDEX, match1); 555 } 556 557 @Test 558 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testAddUidInterfaceRulesGetIfIndexFail()559 public void testAddUidInterfaceRulesGetIfIndexFail() { 560 doReturn(0).when(mDeps).getIfIndex(TEST_IF_NAME); 561 assertThrows(ServiceSpecificException.class, 562 () -> mBpfNetMaps.addUidInterfaceRules(TEST_IF_NAME, TEST_UIDS)); 563 } 564 565 @Test 566 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testAddUidInterfaceRulesWithNullInterface()567 public void testAddUidInterfaceRulesWithNullInterface() throws Exception { 568 final int uid0 = TEST_UIDS[0]; 569 final int uid1 = TEST_UIDS[1]; 570 final long match0 = IIF_MATCH; 571 final long match1 = IIF_MATCH | DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH; 572 mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(TEST_IF_INDEX, match0)); 573 mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(NULL_IIF, match1)); 574 575 mBpfNetMaps.addUidInterfaceRules(null /* ifName */, TEST_UIDS); 576 577 checkUidOwnerValue(uid0, NULL_IIF, match0); 578 checkUidOwnerValue(uid1, NULL_IIF, match1); 579 } 580 doTestRemoveUidInterfaceRules(final int iif0, final long match0, final int iif1, final long match1)581 private void doTestRemoveUidInterfaceRules(final int iif0, final long match0, 582 final int iif1, final long match1) throws Exception { 583 final int uid0 = TEST_UIDS[0]; 584 final int uid1 = TEST_UIDS[1]; 585 mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(iif0, match0)); 586 mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(iif1, match1)); 587 588 mBpfNetMaps.removeUidInterfaceRules(TEST_UIDS); 589 590 checkUidOwnerValue(uid0, NO_IIF, match0 & ~IIF_MATCH); 591 checkUidOwnerValue(uid1, NO_IIF, match1 & ~IIF_MATCH); 592 } 593 594 @Test 595 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testRemoveUidInterfaceRules()596 public void testRemoveUidInterfaceRules() throws Exception { 597 doTestRemoveUidInterfaceRules(TEST_IF_INDEX, IIF_MATCH, NULL_IIF, IIF_MATCH); 598 599 // IIF_MATCH and other matches are enabled 600 doTestRemoveUidInterfaceRules(TEST_IF_INDEX, IIF_MATCH | DOZABLE_MATCH, 601 NULL_IIF, IIF_MATCH | DOZABLE_MATCH | RESTRICTED_MATCH); 602 603 // IIF_MATCH is not enabled 604 doTestRemoveUidInterfaceRules(NO_IIF, DOZABLE_MATCH, 605 NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH); 606 } 607 doTestSetUidRule(final List<Integer> testChains)608 private void doTestSetUidRule(final List<Integer> testChains) throws Exception { 609 mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(TEST_IF_INDEX, IIF_MATCH)); 610 611 for (final int chain: testChains) { 612 final int ruleToAddMatch = mBpfNetMaps.isFirewallAllowList(chain) 613 ? FIREWALL_RULE_ALLOW : FIREWALL_RULE_DENY; 614 mBpfNetMaps.setUidRule(chain, TEST_UID, ruleToAddMatch); 615 } 616 617 checkUidOwnerValue(TEST_UID, TEST_IF_INDEX, IIF_MATCH | getMatch(testChains)); 618 619 for (final int chain: testChains) { 620 final int ruleToRemoveMatch = mBpfNetMaps.isFirewallAllowList(chain) 621 ? FIREWALL_RULE_DENY : FIREWALL_RULE_ALLOW; 622 mBpfNetMaps.setUidRule(chain, TEST_UID, ruleToRemoveMatch); 623 } 624 625 checkUidOwnerValue(TEST_UID, TEST_IF_INDEX, IIF_MATCH); 626 } 627 doTestSetUidRule(final int testChain)628 private void doTestSetUidRule(final int testChain) throws Exception { 629 doTestSetUidRule(List.of(testChain)); 630 } 631 632 @Test 633 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSetUidRule()634 public void testSetUidRule() throws Exception { 635 doTestSetUidRule(FIREWALL_CHAIN_DOZABLE); 636 doTestSetUidRule(FIREWALL_CHAIN_STANDBY); 637 doTestSetUidRule(FIREWALL_CHAIN_POWERSAVE); 638 doTestSetUidRule(FIREWALL_CHAIN_RESTRICTED); 639 doTestSetUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY); 640 doTestSetUidRule(FIREWALL_CHAIN_OEM_DENY_1); 641 doTestSetUidRule(FIREWALL_CHAIN_OEM_DENY_2); 642 doTestSetUidRule(FIREWALL_CHAIN_OEM_DENY_3); 643 } 644 645 @Test 646 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSetUidRuleMultipleChain()647 public void testSetUidRuleMultipleChain() throws Exception { 648 doTestSetUidRule(List.of( 649 FIREWALL_CHAIN_DOZABLE, 650 FIREWALL_CHAIN_STANDBY)); 651 doTestSetUidRule(List.of( 652 FIREWALL_CHAIN_DOZABLE, 653 FIREWALL_CHAIN_STANDBY, 654 FIREWALL_CHAIN_POWERSAVE, 655 FIREWALL_CHAIN_RESTRICTED)); 656 doTestSetUidRule(FIREWALL_CHAINS); 657 } 658 659 @Test 660 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSetUidRuleRemoveRuleFromUidWithNoRule()661 public void testSetUidRuleRemoveRuleFromUidWithNoRule() { 662 final Class<ServiceSpecificException> expected = ServiceSpecificException.class; 663 assertThrows(expected, 664 () -> mBpfNetMaps.setUidRule(FIREWALL_CHAIN_DOZABLE, TEST_UID, FIREWALL_RULE_DENY)); 665 } 666 667 @Test 668 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSetUidRuleInvalidChain()669 public void testSetUidRuleInvalidChain() { 670 final Class<ServiceSpecificException> expected = ServiceSpecificException.class; 671 assertThrows(expected, 672 () -> mBpfNetMaps.setUidRule(-1 /* childChain */, TEST_UID, FIREWALL_RULE_ALLOW)); 673 assertThrows(expected, 674 () -> mBpfNetMaps.setUidRule(1000 /* childChain */, TEST_UID, FIREWALL_RULE_ALLOW)); 675 } 676 677 @Test 678 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSetUidRuleInvalidRule()679 public void testSetUidRuleInvalidRule() { 680 final Class<ServiceSpecificException> expected = ServiceSpecificException.class; 681 assertThrows(expected, () -> 682 mBpfNetMaps.setUidRule(FIREWALL_CHAIN_DOZABLE, TEST_UID, -1 /* firewallRule */)); 683 assertThrows(expected, () -> 684 mBpfNetMaps.setUidRule(FIREWALL_CHAIN_DOZABLE, TEST_UID, 1000 /* firewallRule */)); 685 } 686 687 @Test 688 @IgnoreAfter(Build.VERSION_CODES.S_V2) testSetUidRuleBeforeT()689 public void testSetUidRuleBeforeT() { 690 assertThrows(UnsupportedOperationException.class, () -> 691 mBpfNetMaps.setUidRule(FIREWALL_CHAIN_DOZABLE, TEST_UID, FIREWALL_RULE_ALLOW)); 692 } 693 doTestGetUidRule(final List<Integer> enableChains)694 private void doTestGetUidRule(final List<Integer> enableChains) throws Exception { 695 mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(0, getMatch(enableChains))); 696 697 for (final int chain: FIREWALL_CHAINS) { 698 final String testCase = "EnabledChains: " + enableChains + " CheckedChain: " + chain; 699 if (enableChains.contains(chain)) { 700 final int expectedRule = mBpfNetMaps.isFirewallAllowList(chain) 701 ? FIREWALL_RULE_ALLOW : FIREWALL_RULE_DENY; 702 assertEquals(testCase, expectedRule, mBpfNetMaps.getUidRule(chain, TEST_UID)); 703 } else { 704 final int expectedRule = mBpfNetMaps.isFirewallAllowList(chain) 705 ? FIREWALL_RULE_DENY : FIREWALL_RULE_ALLOW; 706 assertEquals(testCase, expectedRule, mBpfNetMaps.getUidRule(chain, TEST_UID)); 707 } 708 } 709 } 710 doTestGetUidRule(final int enableChain)711 private void doTestGetUidRule(final int enableChain) throws Exception { 712 doTestGetUidRule(List.of(enableChain)); 713 } 714 715 @Test 716 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testGetUidRule()717 public void testGetUidRule() throws Exception { 718 doTestGetUidRule(FIREWALL_CHAIN_DOZABLE); 719 doTestGetUidRule(FIREWALL_CHAIN_STANDBY); 720 doTestGetUidRule(FIREWALL_CHAIN_POWERSAVE); 721 doTestGetUidRule(FIREWALL_CHAIN_RESTRICTED); 722 doTestGetUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY); 723 doTestGetUidRule(FIREWALL_CHAIN_OEM_DENY_1); 724 doTestGetUidRule(FIREWALL_CHAIN_OEM_DENY_2); 725 doTestGetUidRule(FIREWALL_CHAIN_OEM_DENY_3); 726 } 727 728 @Test 729 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testGetUidRuleMultipleChainEnabled()730 public void testGetUidRuleMultipleChainEnabled() throws Exception { 731 doTestGetUidRule(List.of( 732 FIREWALL_CHAIN_DOZABLE, 733 FIREWALL_CHAIN_STANDBY)); 734 doTestGetUidRule(List.of( 735 FIREWALL_CHAIN_DOZABLE, 736 FIREWALL_CHAIN_STANDBY, 737 FIREWALL_CHAIN_POWERSAVE, 738 FIREWALL_CHAIN_RESTRICTED)); 739 doTestGetUidRule(FIREWALL_CHAINS); 740 } 741 742 @Test 743 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testGetUidRuleNoEntry()744 public void testGetUidRuleNoEntry() throws Exception { 745 mUidOwnerMap.clear(); 746 for (final int chain: FIREWALL_CHAINS) { 747 final int expectedRule = mBpfNetMaps.isFirewallAllowList(chain) 748 ? FIREWALL_RULE_DENY : FIREWALL_RULE_ALLOW; 749 assertEquals(expectedRule, mBpfNetMaps.getUidRule(chain, TEST_UID)); 750 } 751 } 752 753 @Test 754 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testGetUidRuleInvalidChain()755 public void testGetUidRuleInvalidChain() { 756 final Class<ServiceSpecificException> expected = ServiceSpecificException.class; 757 assertThrows(expected, () -> mBpfNetMaps.getUidRule(-1 /* childChain */, TEST_UID)); 758 assertThrows(expected, () -> mBpfNetMaps.getUidRule(1000 /* childChain */, TEST_UID)); 759 } 760 761 @Test 762 @IgnoreAfter(Build.VERSION_CODES.S_V2) testGetUidRuleBeforeT()763 public void testGetUidRuleBeforeT() { 764 assertThrows(UnsupportedOperationException.class, 765 () -> mBpfNetMaps.getUidRule(FIREWALL_CHAIN_DOZABLE, TEST_UID)); 766 } 767 768 @Test 769 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testReplaceUidChain()770 public void testReplaceUidChain() throws Exception { 771 final int uid0 = TEST_UIDS[0]; 772 final int uid1 = TEST_UIDS[1]; 773 774 mBpfNetMaps.replaceUidChain(FIREWALL_CHAIN_DOZABLE, TEST_UIDS); 775 776 checkUidOwnerValue(uid0, NO_IIF, DOZABLE_MATCH); 777 checkUidOwnerValue(uid1, NO_IIF, DOZABLE_MATCH); 778 } 779 780 @Test 781 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testReplaceUidChainWithOtherMatch()782 public void testReplaceUidChainWithOtherMatch() throws Exception { 783 final int uid0 = TEST_UIDS[0]; 784 final int uid1 = TEST_UIDS[1]; 785 final long match0 = POWERSAVE_MATCH; 786 final long match1 = POWERSAVE_MATCH | RESTRICTED_MATCH; 787 mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(NO_IIF, match0)); 788 mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(NO_IIF, match1)); 789 790 mBpfNetMaps.replaceUidChain(FIREWALL_CHAIN_DOZABLE, new int[]{uid1}); 791 792 checkUidOwnerValue(uid0, NO_IIF, match0); 793 checkUidOwnerValue(uid1, NO_IIF, match1 | DOZABLE_MATCH); 794 } 795 796 @Test 797 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testReplaceUidChainWithExistingIifMatch()798 public void testReplaceUidChainWithExistingIifMatch() throws Exception { 799 final int uid0 = TEST_UIDS[0]; 800 final int uid1 = TEST_UIDS[1]; 801 final long match0 = IIF_MATCH; 802 final long match1 = IIF_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH; 803 mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(TEST_IF_INDEX, match0)); 804 mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(NULL_IIF, match1)); 805 806 mBpfNetMaps.replaceUidChain(FIREWALL_CHAIN_DOZABLE, TEST_UIDS); 807 808 checkUidOwnerValue(uid0, TEST_IF_INDEX, match0 | DOZABLE_MATCH); 809 checkUidOwnerValue(uid1, NULL_IIF, match1 | DOZABLE_MATCH); 810 } 811 812 @Test 813 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testReplaceUidChainRemoveExistingMatch()814 public void testReplaceUidChainRemoveExistingMatch() throws Exception { 815 final int uid0 = TEST_UIDS[0]; 816 final int uid1 = TEST_UIDS[1]; 817 final long match0 = IIF_MATCH | DOZABLE_MATCH; 818 final long match1 = IIF_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH; 819 mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(TEST_IF_INDEX, match0)); 820 mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(NULL_IIF, match1)); 821 822 mBpfNetMaps.replaceUidChain(FIREWALL_CHAIN_DOZABLE, new int[]{uid1}); 823 824 checkUidOwnerValue(uid0, TEST_IF_INDEX, match0 & ~DOZABLE_MATCH); 825 checkUidOwnerValue(uid1, NULL_IIF, match1 | DOZABLE_MATCH); 826 } 827 828 @Test 829 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testReplaceUidChainInvalidChain()830 public void testReplaceUidChainInvalidChain() { 831 final Class<IllegalArgumentException> expected = IllegalArgumentException.class; 832 assertThrows(expected, () -> mBpfNetMaps.replaceUidChain(-1 /* chain */, TEST_UIDS)); 833 assertThrows(expected, () -> mBpfNetMaps.replaceUidChain(1000 /* chain */, TEST_UIDS)); 834 } 835 836 @Test 837 @IgnoreAfter(Build.VERSION_CODES.S_V2) testReplaceUidChainBeforeT()838 public void testReplaceUidChainBeforeT() { 839 assertThrows(UnsupportedOperationException.class, 840 () -> mBpfNetMaps.replaceUidChain(FIREWALL_CHAIN_DOZABLE, TEST_UIDS)); 841 } 842 843 @Test 844 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSetNetPermForUidsGrantInternetPermission()845 public void testSetNetPermForUidsGrantInternetPermission() throws Exception { 846 mBpfNetMaps.setNetPermForUids(PERMISSION_INTERNET, TEST_UIDS); 847 848 assertTrue(mUidPermissionMap.isEmpty()); 849 } 850 851 @Test 852 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSetNetPermForUidsGrantUpdateStatsPermission()853 public void testSetNetPermForUidsGrantUpdateStatsPermission() throws Exception { 854 mBpfNetMaps.setNetPermForUids(PERMISSION_UPDATE_DEVICE_STATS, TEST_UIDS); 855 856 final int uid0 = TEST_UIDS[0]; 857 final int uid1 = TEST_UIDS[1]; 858 assertEquals(PERMISSION_UPDATE_DEVICE_STATS, mUidPermissionMap.getValue(new S32(uid0)).val); 859 assertEquals(PERMISSION_UPDATE_DEVICE_STATS, mUidPermissionMap.getValue(new S32(uid1)).val); 860 } 861 862 @Test 863 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSetNetPermForUidsGrantMultiplePermissions()864 public void testSetNetPermForUidsGrantMultiplePermissions() throws Exception { 865 final int permission = PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS; 866 mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS); 867 868 final int uid0 = TEST_UIDS[0]; 869 final int uid1 = TEST_UIDS[1]; 870 assertEquals(permission, mUidPermissionMap.getValue(new S32(uid0)).val); 871 assertEquals(permission, mUidPermissionMap.getValue(new S32(uid1)).val); 872 } 873 874 @Test 875 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSetNetPermForUidsRevokeInternetPermission()876 public void testSetNetPermForUidsRevokeInternetPermission() throws Exception { 877 final int uid0 = TEST_UIDS[0]; 878 final int uid1 = TEST_UIDS[1]; 879 mBpfNetMaps.setNetPermForUids(PERMISSION_INTERNET, TEST_UIDS); 880 mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, new int[]{uid0}); 881 882 assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new S32(uid0)).val); 883 assertNull(mUidPermissionMap.getValue(new S32(uid1))); 884 } 885 886 @Test 887 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSetNetPermForUidsRevokeUpdateDeviceStatsPermission()888 public void testSetNetPermForUidsRevokeUpdateDeviceStatsPermission() throws Exception { 889 final int uid0 = TEST_UIDS[0]; 890 final int uid1 = TEST_UIDS[1]; 891 mBpfNetMaps.setNetPermForUids(PERMISSION_UPDATE_DEVICE_STATS, TEST_UIDS); 892 mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, new int[]{uid0}); 893 894 assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new S32(uid0)).val); 895 assertEquals(PERMISSION_UPDATE_DEVICE_STATS, mUidPermissionMap.getValue(new S32(uid1)).val); 896 } 897 898 @Test 899 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSetNetPermForUidsRevokeMultiplePermissions()900 public void testSetNetPermForUidsRevokeMultiplePermissions() throws Exception { 901 final int uid0 = TEST_UIDS[0]; 902 final int uid1 = TEST_UIDS[1]; 903 final int permission = PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS; 904 mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS); 905 mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, new int[]{uid0}); 906 907 assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new S32(uid0)).val); 908 assertEquals(permission, mUidPermissionMap.getValue(new S32(uid1)).val); 909 } 910 911 @Test 912 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSetNetPermForUidsPermissionUninstalled()913 public void testSetNetPermForUidsPermissionUninstalled() throws Exception { 914 final int uid0 = TEST_UIDS[0]; 915 final int uid1 = TEST_UIDS[1]; 916 final int permission = PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS; 917 mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS); 918 mBpfNetMaps.setNetPermForUids(PERMISSION_UNINSTALLED, new int[]{uid0}); 919 920 assertNull(mUidPermissionMap.getValue(new S32(uid0))); 921 assertEquals(permission, mUidPermissionMap.getValue(new S32(uid1)).val); 922 } 923 924 @Test 925 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSetNetPermForUidsDuplicatedRequestSilentlyIgnored()926 public void testSetNetPermForUidsDuplicatedRequestSilentlyIgnored() throws Exception { 927 final int uid0 = TEST_UIDS[0]; 928 final int uid1 = TEST_UIDS[1]; 929 final int permission = PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS; 930 931 mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS); 932 assertEquals(permission, mUidPermissionMap.getValue(new S32(uid0)).val); 933 assertEquals(permission, mUidPermissionMap.getValue(new S32(uid1)).val); 934 935 mBpfNetMaps.setNetPermForUids(permission, TEST_UIDS); 936 assertEquals(permission, mUidPermissionMap.getValue(new S32(uid0)).val); 937 assertEquals(permission, mUidPermissionMap.getValue(new S32(uid1)).val); 938 939 mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, TEST_UIDS); 940 assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new S32(uid0)).val); 941 assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new S32(uid1)).val); 942 943 mBpfNetMaps.setNetPermForUids(PERMISSION_NONE, TEST_UIDS); 944 assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new S32(uid0)).val); 945 assertEquals(PERMISSION_NONE, mUidPermissionMap.getValue(new S32(uid1)).val); 946 947 mBpfNetMaps.setNetPermForUids(PERMISSION_UNINSTALLED, TEST_UIDS); 948 assertNull(mUidPermissionMap.getValue(new S32(uid0))); 949 assertNull(mUidPermissionMap.getValue(new S32(uid1))); 950 951 mBpfNetMaps.setNetPermForUids(PERMISSION_UNINSTALLED, TEST_UIDS); 952 assertNull(mUidPermissionMap.getValue(new S32(uid0))); 953 assertNull(mUidPermissionMap.getValue(new S32(uid1))); 954 } 955 956 @Test 957 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSwapActiveStatsMap()958 public void testSwapActiveStatsMap() throws Exception { 959 mConfigurationMap.updateEntry( 960 CURRENT_STATS_MAP_CONFIGURATION_KEY, new U32(STATS_SELECT_MAP_A)); 961 962 mBpfNetMaps.swapActiveStatsMap(); 963 assertEquals(STATS_SELECT_MAP_B, 964 mConfigurationMap.getValue(CURRENT_STATS_MAP_CONFIGURATION_KEY).val); 965 966 mBpfNetMaps.swapActiveStatsMap(); 967 assertEquals(STATS_SELECT_MAP_A, 968 mConfigurationMap.getValue(CURRENT_STATS_MAP_CONFIGURATION_KEY).val); 969 } 970 971 @Test 972 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testSwapActiveStatsMapSynchronizeKernelRCUFail()973 public void testSwapActiveStatsMapSynchronizeKernelRCUFail() throws Exception { 974 doReturn(EPERM).when(mDeps).synchronizeKernelRCU(); 975 mConfigurationMap.updateEntry( 976 CURRENT_STATS_MAP_CONFIGURATION_KEY, new U32(STATS_SELECT_MAP_A)); 977 978 assertThrows(ServiceSpecificException.class, () -> mBpfNetMaps.swapActiveStatsMap()); 979 } 980 981 @Test 982 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testPullBpfMapInfo()983 public void testPullBpfMapInfo() throws Exception { 984 // mCookieTagMap has 1 entry 985 mCookieTagMap.updateEntry(new CookieTagMapKey(0), new CookieTagMapValue(0, 0)); 986 987 // mUidOwnerMap has 2 entries 988 mUidOwnerMap.updateEntry(new S32(0), new UidOwnerValue(0, 0)); 989 mUidOwnerMap.updateEntry(new S32(1), new UidOwnerValue(0, 0)); 990 991 // mUidPermissionMap has 3 entries 992 mUidPermissionMap.updateEntry(new S32(0), new U8((short) 0)); 993 mUidPermissionMap.updateEntry(new S32(1), new U8((short) 0)); 994 mUidPermissionMap.updateEntry(new S32(2), new U8((short) 0)); 995 996 final int ret = mBpfNetMaps.pullBpfMapInfoAtom(NETWORK_BPF_MAP_INFO, new ArrayList<>()); 997 assertEquals(StatsManager.PULL_SUCCESS, ret); 998 verify(mDeps).buildStatsEvent( 999 1 /* cookieTagMapSize */, 2 /* uidOwnerMapSize */, 3 /* uidPermissionMapSize */); 1000 } 1001 1002 @Test 1003 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testPullBpfMapInfoGetMapSizeFailure()1004 public void testPullBpfMapInfoGetMapSizeFailure() throws Exception { 1005 doThrow(new ErrnoException("", EINVAL)).when(mCookieTagMap).forEach(any()); 1006 final int ret = mBpfNetMaps.pullBpfMapInfoAtom(NETWORK_BPF_MAP_INFO, new ArrayList<>()); 1007 assertEquals(StatsManager.PULL_SKIP, ret); 1008 } 1009 1010 @Test 1011 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testPullBpfMapInfoUnexpectedAtomTag()1012 public void testPullBpfMapInfoUnexpectedAtomTag() { 1013 final int ret = mBpfNetMaps.pullBpfMapInfoAtom(-1 /* atomTag */, new ArrayList<>()); 1014 assertEquals(StatsManager.PULL_SKIP, ret); 1015 } 1016 assertDumpContains(final String dump, final String message)1017 private void assertDumpContains(final String dump, final String message) { 1018 assertTrue(String.format("dump(%s) does not contain '%s'", dump, message), 1019 dump.contains(message)); 1020 } 1021 getDump()1022 private String getDump() throws Exception { 1023 final StringWriter sw = new StringWriter(); 1024 mBpfNetMaps.dump(new IndentingPrintWriter(sw), new FileDescriptor(), true /* verbose */); 1025 return sw.toString(); 1026 } 1027 doTestDumpUidPermissionMap(final int permission, final String permissionString)1028 private void doTestDumpUidPermissionMap(final int permission, final String permissionString) 1029 throws Exception { 1030 mUidPermissionMap.updateEntry(new S32(TEST_UID), new U8((short) permission)); 1031 assertDumpContains(getDump(), TEST_UID + " " + permissionString); 1032 } 1033 1034 @Test 1035 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testDumpUidPermissionMap()1036 public void testDumpUidPermissionMap() throws Exception { 1037 doTestDumpUidPermissionMap(PERMISSION_NONE, "PERMISSION_NONE"); 1038 doTestDumpUidPermissionMap(PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS, 1039 "PERMISSION_INTERNET PERMISSION_UPDATE_DEVICE_STATS"); 1040 } 1041 1042 @Test 1043 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testDumpUidPermissionMapInvalidPermission()1044 public void testDumpUidPermissionMapInvalidPermission() throws Exception { 1045 doTestDumpUidPermissionMap(PERMISSION_UNINSTALLED, "PERMISSION_UNINSTALLED error!"); 1046 doTestDumpUidPermissionMap(PERMISSION_INTERNET | 1 << 6, 1047 "PERMISSION_INTERNET PERMISSION_UNKNOWN(64)"); 1048 } 1049 doTestDumpUidOwnerMap(final int iif, final long match, final String matchString)1050 void doTestDumpUidOwnerMap(final int iif, final long match, final String matchString) 1051 throws Exception { 1052 mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match)); 1053 assertDumpContains(getDump(), TEST_UID + " " + matchString); 1054 } 1055 doTestDumpUidOwnerMap(final long match, final String matchString)1056 void doTestDumpUidOwnerMap(final long match, final String matchString) throws Exception { 1057 doTestDumpUidOwnerMap(0 /* iif */, match, matchString); 1058 } 1059 1060 @Test 1061 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testDumpUidOwnerMap()1062 public void testDumpUidOwnerMap() throws Exception { 1063 doTestDumpUidOwnerMap(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH"); 1064 doTestDumpUidOwnerMap(PENALTY_BOX_MATCH, "PENALTY_BOX_MATCH"); 1065 doTestDumpUidOwnerMap(DOZABLE_MATCH, "DOZABLE_MATCH"); 1066 doTestDumpUidOwnerMap(STANDBY_MATCH, "STANDBY_MATCH"); 1067 doTestDumpUidOwnerMap(POWERSAVE_MATCH, "POWERSAVE_MATCH"); 1068 doTestDumpUidOwnerMap(RESTRICTED_MATCH, "RESTRICTED_MATCH"); 1069 doTestDumpUidOwnerMap(LOW_POWER_STANDBY_MATCH, "LOW_POWER_STANDBY_MATCH"); 1070 doTestDumpUidOwnerMap(LOCKDOWN_VPN_MATCH, "LOCKDOWN_VPN_MATCH"); 1071 doTestDumpUidOwnerMap(OEM_DENY_1_MATCH, "OEM_DENY_1_MATCH"); 1072 doTestDumpUidOwnerMap(OEM_DENY_2_MATCH, "OEM_DENY_2_MATCH"); 1073 doTestDumpUidOwnerMap(OEM_DENY_3_MATCH, "OEM_DENY_3_MATCH"); 1074 1075 doTestDumpUidOwnerMap(HAPPY_BOX_MATCH | POWERSAVE_MATCH, 1076 "HAPPY_BOX_MATCH POWERSAVE_MATCH"); 1077 doTestDumpUidOwnerMap(DOZABLE_MATCH | LOCKDOWN_VPN_MATCH | OEM_DENY_1_MATCH, 1078 "DOZABLE_MATCH LOCKDOWN_VPN_MATCH OEM_DENY_1_MATCH"); 1079 } 1080 1081 @Test 1082 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testDumpUidOwnerMapWithIifMatch()1083 public void testDumpUidOwnerMapWithIifMatch() throws Exception { 1084 doTestDumpUidOwnerMap(TEST_IF_INDEX, IIF_MATCH, "IIF_MATCH " + TEST_IF_INDEX); 1085 doTestDumpUidOwnerMap(TEST_IF_INDEX, 1086 IIF_MATCH | DOZABLE_MATCH | LOCKDOWN_VPN_MATCH | OEM_DENY_1_MATCH, 1087 "DOZABLE_MATCH IIF_MATCH LOCKDOWN_VPN_MATCH OEM_DENY_1_MATCH " + TEST_IF_INDEX); 1088 } 1089 1090 @Test 1091 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testDumpUidOwnerMapWithInvalidMatch()1092 public void testDumpUidOwnerMapWithInvalidMatch() throws Exception { 1093 final long invalid_match = 1L << 31; 1094 doTestDumpUidOwnerMap(invalid_match, "UNKNOWN_MATCH(" + invalid_match + ")"); 1095 doTestDumpUidOwnerMap(DOZABLE_MATCH | invalid_match, 1096 "DOZABLE_MATCH UNKNOWN_MATCH(" + invalid_match + ")"); 1097 } 1098 1099 @Test 1100 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testDumpCurrentStatsMapConfig()1101 public void testDumpCurrentStatsMapConfig() throws Exception { 1102 mConfigurationMap.updateEntry( 1103 CURRENT_STATS_MAP_CONFIGURATION_KEY, new U32(STATS_SELECT_MAP_A)); 1104 assertDumpContains(getDump(), "current statsMap configuration: 0 SELECT_MAP_A"); 1105 1106 mConfigurationMap.updateEntry( 1107 CURRENT_STATS_MAP_CONFIGURATION_KEY, new U32(STATS_SELECT_MAP_B)); 1108 assertDumpContains(getDump(), "current statsMap configuration: 1 SELECT_MAP_B"); 1109 } 1110 doTestDumpOwnerMatchConfig(final long match, final String matchString)1111 private void doTestDumpOwnerMatchConfig(final long match, final String matchString) 1112 throws Exception { 1113 mConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(match)); 1114 assertDumpContains(getDump(), 1115 "current ownerMatch configuration: " + match + " " + matchString); 1116 } 1117 1118 @Test 1119 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testDumpUidOwnerMapConfig()1120 public void testDumpUidOwnerMapConfig() throws Exception { 1121 doTestDumpOwnerMatchConfig(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH"); 1122 doTestDumpOwnerMatchConfig(PENALTY_BOX_MATCH, "PENALTY_BOX_MATCH"); 1123 doTestDumpOwnerMatchConfig(DOZABLE_MATCH, "DOZABLE_MATCH"); 1124 doTestDumpOwnerMatchConfig(STANDBY_MATCH, "STANDBY_MATCH"); 1125 doTestDumpOwnerMatchConfig(POWERSAVE_MATCH, "POWERSAVE_MATCH"); 1126 doTestDumpOwnerMatchConfig(RESTRICTED_MATCH, "RESTRICTED_MATCH"); 1127 doTestDumpOwnerMatchConfig(LOW_POWER_STANDBY_MATCH, "LOW_POWER_STANDBY_MATCH"); 1128 doTestDumpOwnerMatchConfig(IIF_MATCH, "IIF_MATCH"); 1129 doTestDumpOwnerMatchConfig(LOCKDOWN_VPN_MATCH, "LOCKDOWN_VPN_MATCH"); 1130 doTestDumpOwnerMatchConfig(OEM_DENY_1_MATCH, "OEM_DENY_1_MATCH"); 1131 doTestDumpOwnerMatchConfig(OEM_DENY_2_MATCH, "OEM_DENY_2_MATCH"); 1132 doTestDumpOwnerMatchConfig(OEM_DENY_3_MATCH, "OEM_DENY_3_MATCH"); 1133 1134 doTestDumpOwnerMatchConfig(HAPPY_BOX_MATCH | POWERSAVE_MATCH, 1135 "HAPPY_BOX_MATCH POWERSAVE_MATCH"); 1136 doTestDumpOwnerMatchConfig(DOZABLE_MATCH | LOCKDOWN_VPN_MATCH | OEM_DENY_1_MATCH, 1137 "DOZABLE_MATCH LOCKDOWN_VPN_MATCH OEM_DENY_1_MATCH"); 1138 } 1139 1140 @Test 1141 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testDumpUidOwnerMapConfigWithInvalidMatch()1142 public void testDumpUidOwnerMapConfigWithInvalidMatch() throws Exception { 1143 final long invalid_match = 1L << 31; 1144 doTestDumpOwnerMatchConfig(invalid_match, "UNKNOWN_MATCH(" + invalid_match + ")"); 1145 doTestDumpOwnerMatchConfig(DOZABLE_MATCH | invalid_match, 1146 "DOZABLE_MATCH UNKNOWN_MATCH(" + invalid_match + ")"); 1147 } 1148 1149 @Test 1150 @IgnoreUpTo(Build.VERSION_CODES.S_V2) testDumpCookieTagMap()1151 public void testDumpCookieTagMap() throws Exception { 1152 mCookieTagMap.updateEntry(new CookieTagMapKey(123), new CookieTagMapValue(456, 0x789)); 1153 assertDumpContains(getDump(), "cookie=123 tag=0x789 uid=456"); 1154 } 1155 1156 @Test testGetUids()1157 public void testGetUids() throws ErrnoException { 1158 final int uid0 = TEST_UIDS[0]; 1159 final int uid1 = TEST_UIDS[1]; 1160 final long match0 = DOZABLE_MATCH | POWERSAVE_MATCH; 1161 final long match1 = DOZABLE_MATCH | STANDBY_MATCH; 1162 mUidOwnerMap.updateEntry(new S32(uid0), new UidOwnerValue(NULL_IIF, match0)); 1163 mUidOwnerMap.updateEntry(new S32(uid1), new UidOwnerValue(NULL_IIF, match1)); 1164 1165 assertEquals(new ArraySet<>(List.of(uid0, uid1)), 1166 mBpfNetMaps.getUidsWithAllowRuleOnAllowListChain(FIREWALL_CHAIN_DOZABLE)); 1167 assertEquals(new ArraySet<>(List.of(uid0)), 1168 mBpfNetMaps.getUidsWithAllowRuleOnAllowListChain(FIREWALL_CHAIN_POWERSAVE)); 1169 1170 assertEquals(new ArraySet<>(List.of(uid1)), 1171 mBpfNetMaps.getUidsWithDenyRuleOnDenyListChain(FIREWALL_CHAIN_STANDBY)); 1172 assertEquals(new ArraySet<>(), 1173 mBpfNetMaps.getUidsWithDenyRuleOnDenyListChain(FIREWALL_CHAIN_OEM_DENY_1)); 1174 } 1175 1176 @Test testGetUidsIllegalArgument()1177 public void testGetUidsIllegalArgument() { 1178 final Class<IllegalArgumentException> expected = IllegalArgumentException.class; 1179 assertThrows(expected, 1180 () -> mBpfNetMaps.getUidsWithDenyRuleOnDenyListChain(FIREWALL_CHAIN_DOZABLE)); 1181 assertThrows(expected, 1182 () -> mBpfNetMaps.getUidsWithAllowRuleOnAllowListChain(FIREWALL_CHAIN_OEM_DENY_1)); 1183 } 1184 } 1185