Use java BpfMap in BpfNetMaps#removeNaughtyApp

Bug: 217624062
Test: atest BpfNetMapsTest HostsideRestrictBackgroundNetworkTests
Change-Id: Ibfb3ae48427b7dc5d06708e63f4a16f7527ce86c
This commit is contained in:
Motomu Utsumi
2022-06-24 10:38:57 +00:00
parent 5a68a21926
commit 60ed3be43b
2 changed files with 104 additions and 20 deletions

View File

@@ -25,6 +25,7 @@ import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED; import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY; import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
import static android.system.OsConstants.EINVAL; import static android.system.OsConstants.EINVAL;
import static android.system.OsConstants.ENOENT;
import static android.system.OsConstants.EOPNOTSUPP; import static android.system.OsConstants.EOPNOTSUPP;
import android.net.INetd; import android.net.INetd;
@@ -77,19 +78,19 @@ public class BpfNetMaps {
private static BpfMap<U32, UidOwnerValue> sUidOwnerMap = null; private static BpfMap<U32, UidOwnerValue> sUidOwnerMap = null;
// LINT.IfChange(match_type) // LINT.IfChange(match_type)
private static final long NO_MATCH = 0; @VisibleForTesting public static final long NO_MATCH = 0;
private static final long HAPPY_BOX_MATCH = (1 << 0); @VisibleForTesting public static final long HAPPY_BOX_MATCH = (1 << 0);
private static final long PENALTY_BOX_MATCH = (1 << 1); @VisibleForTesting public static final long PENALTY_BOX_MATCH = (1 << 1);
private static final long DOZABLE_MATCH = (1 << 2); @VisibleForTesting public static final long DOZABLE_MATCH = (1 << 2);
private static final long STANDBY_MATCH = (1 << 3); @VisibleForTesting public static final long STANDBY_MATCH = (1 << 3);
private static final long POWERSAVE_MATCH = (1 << 4); @VisibleForTesting public static final long POWERSAVE_MATCH = (1 << 4);
private static final long RESTRICTED_MATCH = (1 << 5); @VisibleForTesting public static final long RESTRICTED_MATCH = (1 << 5);
private static final long LOW_POWER_STANDBY_MATCH = (1 << 6); @VisibleForTesting public static final long LOW_POWER_STANDBY_MATCH = (1 << 6);
private static final long IIF_MATCH = (1 << 7); @VisibleForTesting public static final long IIF_MATCH = (1 << 7);
private static final long LOCKDOWN_VPN_MATCH = (1 << 8); @VisibleForTesting public static final long LOCKDOWN_VPN_MATCH = (1 << 8);
private static final long OEM_DENY_1_MATCH = (1 << 9); @VisibleForTesting public static final long OEM_DENY_1_MATCH = (1 << 9);
private static final long OEM_DENY_2_MATCH = (1 << 10); @VisibleForTesting public static final long OEM_DENY_2_MATCH = (1 << 10);
private static final long OEM_DENY_3_MATCH = (1 << 11); @VisibleForTesting public static final long OEM_DENY_3_MATCH = (1 << 11);
// LINT.ThenChange(packages/modules/Connectivity/bpf_progs/bpf_shared.h) // LINT.ThenChange(packages/modules/Connectivity/bpf_progs/bpf_shared.h)
// TODO: Use Java BpfMap instead of JNI code (TrafficController) for map update. // TODO: Use Java BpfMap instead of JNI code (TrafficController) for map update.
@@ -200,6 +201,33 @@ public class BpfNetMaps {
} }
} }
private void removeRule(final int uid, final long match, final String caller) {
try {
synchronized (sUidOwnerMap) {
final UidOwnerValue oldMatch = sUidOwnerMap.getValue(new U32(uid));
if (oldMatch == null) {
throw new ServiceSpecificException(ENOENT,
"sUidOwnerMap does not have entry for uid: " + uid);
}
final UidOwnerValue newMatch = new UidOwnerValue(
(match == IIF_MATCH) ? 0 : oldMatch.iif,
oldMatch.rule & ~match
);
if (newMatch.rule == 0) {
sUidOwnerMap.deleteEntry(new U32(uid));
} else {
sUidOwnerMap.updateEntry(new U32(uid), newMatch);
}
}
} catch (ErrnoException e) {
throw new ServiceSpecificException(e.errno,
caller + " failed to remove rule: " + Os.strerror(e.errno));
}
}
/** /**
* Add naughty app bandwidth rule for specific app * Add naughty app bandwidth rule for specific app
* *
@@ -222,10 +250,8 @@ public class BpfNetMaps {
* cause of the failure. * cause of the failure.
*/ */
public void removeNaughtyApp(final int uid) { public void removeNaughtyApp(final int uid) {
synchronized (sUidOwnerMap) { throwIfPreT("removeNaughtyApp is not available on pre-T devices");
final int err = native_removeNaughtyApp(uid); removeRule(uid, PENALTY_BOX_MATCH, "removeNaughtyApp");
maybeThrow(err, "Unable to remove naughty app");
}
} }
/** /**

View File

@@ -26,8 +26,15 @@ import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY; import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
import static android.net.INetd.PERMISSION_INTERNET; import static android.net.INetd.PERMISSION_INTERNET;
import static com.android.server.BpfNetMaps.DOZABLE_MATCH;
import static com.android.server.BpfNetMaps.IIF_MATCH;
import static com.android.server.BpfNetMaps.PENALTY_BOX_MATCH;
import static com.android.server.BpfNetMaps.POWERSAVE_MATCH;
import static com.android.server.BpfNetMaps.RESTRICTED_MATCH;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeFalse;
@@ -68,7 +75,9 @@ public final class BpfNetMapsTest {
private static final int TEST_UID = 10086; private static final int TEST_UID = 10086;
private static final int[] TEST_UIDS = {10002, 10003}; private static final int[] TEST_UIDS = {10002, 10003};
private static final String IFNAME = "wlan0"; 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 String CHAINNAME = "fw_dozable"; private static final String CHAINNAME = "fw_dozable";
private static final U32 UID_RULES_CONFIGURATION_KEY = new U32(0); private static final U32 UID_RULES_CONFIGURATION_KEY = new U32(0);
private static final List<Integer> FIREWALL_CHAINS = List.of( private static final List<Integer> FIREWALL_CHAINS = List.of(
@@ -100,8 +109,8 @@ public final class BpfNetMapsTest {
@Test @Test
public void testBpfNetMapsBeforeT() throws Exception { public void testBpfNetMapsBeforeT() throws Exception {
assumeFalse(SdkLevel.isAtLeastT()); assumeFalse(SdkLevel.isAtLeastT());
mBpfNetMaps.addUidInterfaceRules(IFNAME, TEST_UIDS); mBpfNetMaps.addUidInterfaceRules(TEST_IF_NAME, TEST_UIDS);
verify(mNetd).firewallAddUidInterfaceRules(IFNAME, TEST_UIDS); verify(mNetd).firewallAddUidInterfaceRules(TEST_IF_NAME, TEST_UIDS);
mBpfNetMaps.removeUidInterfaceRules(TEST_UIDS); mBpfNetMaps.removeUidInterfaceRules(TEST_UIDS);
verify(mNetd).firewallRemoveUidInterfaceRules(TEST_UIDS); verify(mNetd).firewallRemoveUidInterfaceRules(TEST_UIDS);
mBpfNetMaps.setNetPermForUids(PERMISSION_INTERNET, TEST_UIDS); mBpfNetMaps.setNetPermForUids(PERMISSION_INTERNET, TEST_UIDS);
@@ -241,4 +250,53 @@ public final class BpfNetMapsTest {
assertThrows(UnsupportedOperationException.class, assertThrows(UnsupportedOperationException.class,
() -> mBpfNetMaps.setChildChain(FIREWALL_CHAIN_DOZABLE, true /* enable */)); () -> mBpfNetMaps.setChildChain(FIREWALL_CHAIN_DOZABLE, true /* enable */));
} }
private void checkUidOwnerValue(final long uid, final long expectedIif,
final long expectedMatch) throws Exception {
final UidOwnerValue config = mUidOwnerMap.getValue(new U32(uid));
if (expectedMatch == 0) {
assertNull(config);
} else {
assertEquals(expectedIif, config.iif);
assertEquals(expectedMatch, config.rule);
}
}
private void doTestRemoveNaughtyApp(final long iif, final long match) throws Exception {
mUidOwnerMap.updateEntry(new U32(TEST_UID), new UidOwnerValue(iif, match));
mBpfNetMaps.removeNaughtyApp(TEST_UID);
checkUidOwnerValue(TEST_UID, iif, match & ~PENALTY_BOX_MATCH);
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
public void testRemoveNaughtyApp() throws Exception {
doTestRemoveNaughtyApp(NO_IIF, PENALTY_BOX_MATCH);
// PENALTY_BOX_MATCH with other matches
doTestRemoveNaughtyApp(NO_IIF, PENALTY_BOX_MATCH | DOZABLE_MATCH | POWERSAVE_MATCH);
// PENALTY_BOX_MATCH with IIF_MATCH
doTestRemoveNaughtyApp(TEST_IF_INDEX, PENALTY_BOX_MATCH | IIF_MATCH);
// PENALTY_BOX_MATCH is not enabled
doTestRemoveNaughtyApp(NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH);
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
public void testRemoveNaughtyAppMissingUid() {
// UidOwnerMap does not have entry for TEST_UID
assertThrows(ServiceSpecificException.class,
() -> mBpfNetMaps.removeNaughtyApp(TEST_UID));
}
@Test
@IgnoreAfter(Build.VERSION_CODES.S_V2)
public void testRemoveNaughtyAppBeforeT() {
assertThrows(UnsupportedOperationException.class,
() -> mBpfNetMaps.removeNaughtyApp(TEST_UID));
}
} }