Use java BpfMap in BpfNetMaps#addUidInterfaceRules
Bug: 217624062
Test: atest BpfNetMapsTest HostsideVpnTests#testBlockIncomingPacket
Change-Id: I8aeb4712c852167d553eb331f32d770582199b13
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index 6599c7f..f0e9ec4 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -25,6 +25,7 @@
import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
import static android.system.OsConstants.EINVAL;
+import static android.system.OsConstants.ENODEV;
import static android.system.OsConstants.ENOENT;
import static android.system.OsConstants.EOPNOTSUPP;
@@ -60,6 +61,7 @@
private static final String TAG = "BpfNetMaps";
private final INetd mNetd;
+ private final Dependencies mDeps;
// Use legacy netd for releases before T.
private static boolean sInitialized = false;
@@ -163,6 +165,19 @@
sInitialized = true;
}
+ /**
+ * Dependencies of BpfNetMaps, for injection in tests.
+ */
+ @VisibleForTesting
+ public static class Dependencies {
+ /**
+ * Get interface index.
+ */
+ public int getIfIndex(final String ifName) {
+ return Os.if_nametoindex(ifName);
+ }
+ }
+
/** Constructor used after T that doesn't need to use netd anymore. */
public BpfNetMaps() {
this(null);
@@ -171,10 +186,16 @@
}
public BpfNetMaps(final INetd netd) {
+ this(netd, new Dependencies());
+ }
+
+ @VisibleForTesting
+ public BpfNetMaps(final INetd netd, final Dependencies deps) {
if (!PRE_T) {
ensureInitialized();
}
mNetd = netd;
+ mDeps = deps;
}
/**
@@ -419,9 +440,24 @@
mNetd.firewallAddUidInterfaceRules(ifName, uids);
return;
}
- synchronized (sUidOwnerMap) {
- final int err = native_addUidInterfaceRules(ifName, uids);
- maybeThrow(err, "Unable to add uid interface rules");
+ // Null ifName is a wildcard to allow apps to receive packets on all interfaces and ifIndex
+ // is set to 0.
+ final int ifIndex;
+ if (ifName == null) {
+ ifIndex = 0;
+ } else {
+ ifIndex = mDeps.getIfIndex(ifName);
+ if (ifIndex == 0) {
+ throw new ServiceSpecificException(ENODEV,
+ "Failed to get index of interface " + ifName);
+ }
+ }
+ for (final int uid: uids) {
+ try {
+ addRule(uid, IIF_MATCH, ifIndex, "addUidInterfaceRules");
+ } catch (ServiceSpecificException e) {
+ Log.e(TAG, "addRule failed uid=" + uid + " ifName=" + ifName + ", " + e);
+ }
}
}
diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java
index 433b892..1148e11 100644
--- a/tests/unit/java/com/android/server/BpfNetMapsTest.java
+++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java
@@ -41,6 +41,7 @@
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import android.net.INetd;
@@ -81,6 +82,7 @@
private static final String TEST_IF_NAME = "wlan0";
private static final int TEST_IF_INDEX = 7;
private static final int NO_IIF = 0;
+ private static final int NULL_IIF = 0;
private static final String CHAINNAME = "fw_dozable";
private static final U32 UID_RULES_CONFIGURATION_KEY = new U32(0);
private static final List<Integer> FIREWALL_CHAINS = List.of(
@@ -97,6 +99,7 @@
private BpfNetMaps mBpfNetMaps;
@Mock INetd mNetd;
+ @Mock BpfNetMaps.Dependencies mDeps;
private final BpfMap<U32, U32> mConfigurationMap = new TestBpfMap<>(U32.class, U32.class);
private final BpfMap<U32, UidOwnerValue> mUidOwnerMap =
new TestBpfMap<>(U32.class, UidOwnerValue.class);
@@ -104,9 +107,10 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ doReturn(TEST_IF_INDEX).when(mDeps).getIfIndex(TEST_IF_NAME);
BpfNetMaps.setConfigurationMapForTest(mConfigurationMap);
BpfNetMaps.setUidOwnerMapForTest(mUidOwnerMap);
- mBpfNetMaps = new BpfNetMaps(mNetd);
+ mBpfNetMaps = new BpfNetMaps(mNetd, mDeps);
}
@Test
@@ -458,4 +462,72 @@
assertThrows(UnsupportedOperationException.class,
() -> mBpfNetMaps.updateUidLockdownRule(TEST_UID, true /* add */));
}
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testAddUidInterfaceRules() throws Exception {
+ final int uid0 = TEST_UIDS[0];
+ final int uid1 = TEST_UIDS[1];
+
+ mBpfNetMaps.addUidInterfaceRules(TEST_IF_NAME, TEST_UIDS);
+
+ checkUidOwnerValue(uid0, TEST_IF_INDEX, IIF_MATCH);
+ checkUidOwnerValue(uid1, TEST_IF_INDEX, IIF_MATCH);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testAddUidInterfaceRulesWithOtherMatch() throws Exception {
+ final int uid0 = TEST_UIDS[0];
+ final int uid1 = TEST_UIDS[1];
+ final long match0 = DOZABLE_MATCH;
+ final long match1 = DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH;
+ mUidOwnerMap.updateEntry(new U32(uid0), new UidOwnerValue(NO_IIF, match0));
+ mUidOwnerMap.updateEntry(new U32(uid1), new UidOwnerValue(NO_IIF, match1));
+
+ mBpfNetMaps.addUidInterfaceRules(TEST_IF_NAME, TEST_UIDS);
+
+ checkUidOwnerValue(uid0, TEST_IF_INDEX, match0 | IIF_MATCH);
+ checkUidOwnerValue(uid1, TEST_IF_INDEX, match1 | IIF_MATCH);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testAddUidInterfaceRulesWithExistingIifMatch() throws Exception {
+ final int uid0 = TEST_UIDS[0];
+ final int uid1 = TEST_UIDS[1];
+ final long match0 = IIF_MATCH;
+ final long match1 = IIF_MATCH | DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH;
+ mUidOwnerMap.updateEntry(new U32(uid0), new UidOwnerValue(TEST_IF_INDEX + 1, match0));
+ mUidOwnerMap.updateEntry(new U32(uid1), new UidOwnerValue(NULL_IIF, match1));
+
+ mBpfNetMaps.addUidInterfaceRules(TEST_IF_NAME, TEST_UIDS);
+
+ checkUidOwnerValue(uid0, TEST_IF_INDEX, match0);
+ checkUidOwnerValue(uid1, TEST_IF_INDEX, match1);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testAddUidInterfaceRulesGetIfIndexFail() {
+ doReturn(0).when(mDeps).getIfIndex(TEST_IF_NAME);
+ assertThrows(ServiceSpecificException.class,
+ () -> mBpfNetMaps.addUidInterfaceRules(TEST_IF_NAME, TEST_UIDS));
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testAddUidInterfaceRulesWithNullInterface() throws Exception {
+ final int uid0 = TEST_UIDS[0];
+ final int uid1 = TEST_UIDS[1];
+ final long match0 = IIF_MATCH;
+ final long match1 = IIF_MATCH | DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH;
+ mUidOwnerMap.updateEntry(new U32(uid0), new UidOwnerValue(TEST_IF_INDEX, match0));
+ mUidOwnerMap.updateEntry(new U32(uid1), new UidOwnerValue(NULL_IIF, match1));
+
+ mBpfNetMaps.addUidInterfaceRules(null /* ifName */, TEST_UIDS);
+
+ checkUidOwnerValue(uid0, NULL_IIF, match0);
+ checkUidOwnerValue(uid1, NULL_IIF, match1);
+ }
}