Use java BpfMap in BpfNetMaps#setChildChain
Bug: 217624062 Test: atest BpfNetMapsTest android.net.cts.ConnectivityManagerTest#testFirewallBlocking Change-Id: I13e96911eccd7d1d0545a156ddc2859bcaac09eb
This commit is contained in:
@@ -5903,6 +5903,7 @@ public class ConnectivityManager {
|
||||
*
|
||||
* @param chain target chain.
|
||||
* @param enable whether the chain should be enabled.
|
||||
* @throws UnsupportedOperationException if called on pre-T devices.
|
||||
* @throws IllegalStateException if enabling or disabling the firewall chain failed.
|
||||
* @hide
|
||||
*/
|
||||
@@ -5926,7 +5927,6 @@ public class ConnectivityManager {
|
||||
* @param chain target chain.
|
||||
* @return {@code true} if chain is enabled, {@code false} if chain is disabled.
|
||||
* @throws UnsupportedOperationException if called on pre-T devices.
|
||||
* @throws IllegalArgumentException if {@code chain} is a invalid value.
|
||||
* @throws ServiceSpecificException in case of failure, with an error code indicating the
|
||||
* cause of the failure.
|
||||
* @hide
|
||||
|
||||
@@ -24,6 +24,7 @@ import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3;
|
||||
import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
|
||||
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.ENOENT;
|
||||
import static android.system.OsConstants.EOPNOTSUPP;
|
||||
|
||||
@@ -55,6 +56,11 @@ public class BpfNetMaps {
|
||||
private static final boolean USE_NETD = !SdkLevel.isAtLeastT();
|
||||
private static boolean sInitialized = false;
|
||||
|
||||
// Lock for sConfigurationMap entry for UID_RULES_CONFIGURATION_KEY.
|
||||
// This entry is not accessed by others.
|
||||
// BpfNetMaps acquires this lock while sequence of read, modify, and write.
|
||||
private static final Object sUidRulesConfigBpfMapLock = new Object();
|
||||
|
||||
private static final String CONFIGURATION_MAP_PATH =
|
||||
"/sys/fs/bpf/netd_shared/map_netd_configuration_map";
|
||||
private static final U32 UID_RULES_CONFIGURATION_KEY = new U32(0);
|
||||
@@ -152,7 +158,7 @@ public class BpfNetMaps {
|
||||
public long getMatchByFirewallChain(final int chain) {
|
||||
final long match = FIREWALL_CHAIN_TO_MATCH.get(chain, NO_MATCH);
|
||||
if (match == NO_MATCH) {
|
||||
throw new IllegalArgumentException("Invalid firewall chain: " + chain);
|
||||
throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain);
|
||||
}
|
||||
return match;
|
||||
}
|
||||
@@ -163,6 +169,12 @@ public class BpfNetMaps {
|
||||
}
|
||||
}
|
||||
|
||||
private void throwIfUseNetd(final String msg) {
|
||||
if (USE_NETD) {
|
||||
throw new UnsupportedOperationException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add naughty app bandwidth rule for specific app
|
||||
*
|
||||
@@ -216,12 +228,29 @@ public class BpfNetMaps {
|
||||
*
|
||||
* @param childChain target chain to enable
|
||||
* @param enable whether to enable or disable child chain.
|
||||
* @throws UnsupportedOperationException if called on pre-T devices.
|
||||
* @throws ServiceSpecificException in case of failure, with an error code indicating the
|
||||
* cause of the failure.
|
||||
*/
|
||||
public void setChildChain(final int childChain, final boolean enable) {
|
||||
final int err = native_setChildChain(childChain, enable);
|
||||
maybeThrow(err, "Unable to set child chain");
|
||||
throwIfUseNetd("setChildChain is not available on pre-T devices");
|
||||
|
||||
final long match = getMatchByFirewallChain(childChain);
|
||||
try {
|
||||
synchronized (sUidRulesConfigBpfMapLock) {
|
||||
final U32 config = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY);
|
||||
if (config == null) {
|
||||
throw new ServiceSpecificException(ENOENT,
|
||||
"Unable to get firewall chain status: sConfigurationMap does not have"
|
||||
+ " entry for UID_RULES_CONFIGURATION_KEY");
|
||||
}
|
||||
final long newConfig = enable ? (config.val | match) : (config.val & (~match));
|
||||
sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(newConfig));
|
||||
}
|
||||
} catch (ErrnoException e) {
|
||||
throw new ServiceSpecificException(e.errno,
|
||||
"Unable to set child chain: " + Os.strerror(e.errno));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,15 +259,11 @@ public class BpfNetMaps {
|
||||
* @param childChain target chain
|
||||
* @return {@code true} if chain is enabled, {@code false} if chain is not enabled.
|
||||
* @throws UnsupportedOperationException if called on pre-T devices.
|
||||
* @throws IllegalArgumentException if {@code childChain} is a invalid value.
|
||||
* @throws ServiceSpecificException in case of failure, with an error code indicating the
|
||||
* cause of the failure.
|
||||
*/
|
||||
public boolean getChainEnabled(final int childChain) {
|
||||
if (USE_NETD) {
|
||||
throw new UnsupportedOperationException("getChainEnabled is not available on pre-T"
|
||||
+ " devices");
|
||||
}
|
||||
throwIfUseNetd("getChainEnabled is not available on pre-T devices");
|
||||
|
||||
final long match = getMatchByFirewallChain(childChain);
|
||||
try {
|
||||
|
||||
@@ -26,6 +26,7 @@ import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
|
||||
import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
|
||||
import static android.net.INetd.PERMISSION_INTERNET;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -168,7 +169,7 @@ public final class BpfNetMapsTest {
|
||||
@Test
|
||||
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||
public void testGetChainEnabledInvalidChain() {
|
||||
final Class<IllegalArgumentException> expected = IllegalArgumentException.class;
|
||||
final Class<ServiceSpecificException> expected = ServiceSpecificException.class;
|
||||
assertThrows(expected, () -> mBpfNetMaps.getChainEnabled(-1 /* childChain */));
|
||||
assertThrows(expected, () -> mBpfNetMaps.getChainEnabled(1000 /* childChain */));
|
||||
}
|
||||
@@ -187,4 +188,81 @@ public final class BpfNetMapsTest {
|
||||
assertThrows(UnsupportedOperationException.class,
|
||||
() -> mBpfNetMaps.getChainEnabled(FIREWALL_CHAIN_DOZABLE));
|
||||
}
|
||||
|
||||
private void doTestSetChildChain(final List<Integer> testChains) throws Exception {
|
||||
long expectedMatch = 0;
|
||||
for (final int chain: testChains) {
|
||||
expectedMatch |= mBpfNetMaps.getMatchByFirewallChain(chain);
|
||||
}
|
||||
|
||||
assertEquals(0, sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val);
|
||||
|
||||
for (final int chain: testChains) {
|
||||
mBpfNetMaps.setChildChain(chain, true /* enable */);
|
||||
}
|
||||
assertEquals(expectedMatch, sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val);
|
||||
|
||||
for (final int chain: testChains) {
|
||||
mBpfNetMaps.setChildChain(chain, false /* enable */);
|
||||
}
|
||||
assertEquals(0, sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val);
|
||||
}
|
||||
|
||||
private void doTestSetChildChain(final int testChain) throws Exception {
|
||||
doTestSetChildChain(List.of(testChain));
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||
public void testSetChildChain() throws Exception {
|
||||
sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(0));
|
||||
doTestSetChildChain(FIREWALL_CHAIN_DOZABLE);
|
||||
doTestSetChildChain(FIREWALL_CHAIN_STANDBY);
|
||||
doTestSetChildChain(FIREWALL_CHAIN_POWERSAVE);
|
||||
doTestSetChildChain(FIREWALL_CHAIN_RESTRICTED);
|
||||
doTestSetChildChain(FIREWALL_CHAIN_LOW_POWER_STANDBY);
|
||||
doTestSetChildChain(FIREWALL_CHAIN_OEM_DENY_1);
|
||||
doTestSetChildChain(FIREWALL_CHAIN_OEM_DENY_2);
|
||||
doTestSetChildChain(FIREWALL_CHAIN_OEM_DENY_3);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||
public void testSetChildChainMultipleChain() throws Exception {
|
||||
sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(0));
|
||||
doTestSetChildChain(List.of(
|
||||
FIREWALL_CHAIN_DOZABLE,
|
||||
FIREWALL_CHAIN_STANDBY));
|
||||
doTestSetChildChain(List.of(
|
||||
FIREWALL_CHAIN_DOZABLE,
|
||||
FIREWALL_CHAIN_STANDBY,
|
||||
FIREWALL_CHAIN_POWERSAVE,
|
||||
FIREWALL_CHAIN_RESTRICTED));
|
||||
doTestSetChildChain(FIREWALL_CHAINS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||
public void testSetChildChainInvalidChain() {
|
||||
final Class<ServiceSpecificException> expected = ServiceSpecificException.class;
|
||||
assertThrows(expected,
|
||||
() -> mBpfNetMaps.setChildChain(-1 /* childChain */, true /* enable */));
|
||||
assertThrows(expected,
|
||||
() -> mBpfNetMaps.setChildChain(1000 /* childChain */, true /* enable */));
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||
public void testSetChildChainMissingConfiguration() {
|
||||
// sConfigurationMap does not have entry for UID_RULES_CONFIGURATION_KEY
|
||||
assertThrows(ServiceSpecificException.class,
|
||||
() -> mBpfNetMaps.setChildChain(FIREWALL_CHAIN_DOZABLE, true /* enable */));
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreAfter(Build.VERSION_CODES.S_V2)
|
||||
public void testSetChildChainBeforeT() {
|
||||
assertThrows(UnsupportedOperationException.class,
|
||||
() -> mBpfNetMaps.setChildChain(FIREWALL_CHAIN_DOZABLE, true /* enable */));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user