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 chain target chain.
|
||||||
* @param enable whether the chain should be enabled.
|
* @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.
|
* @throws IllegalStateException if enabling or disabling the firewall chain failed.
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@@ -5926,7 +5927,6 @@ public class ConnectivityManager {
|
|||||||
* @param chain target chain.
|
* @param chain target chain.
|
||||||
* @return {@code true} if chain is enabled, {@code false} if chain is disabled.
|
* @return {@code true} if chain is enabled, {@code false} if chain is disabled.
|
||||||
* @throws UnsupportedOperationException if called on pre-T devices.
|
* @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
|
* @throws ServiceSpecificException in case of failure, with an error code indicating the
|
||||||
* cause of the failure.
|
* cause of the failure.
|
||||||
* @hide
|
* @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_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.ENOENT;
|
import static android.system.OsConstants.ENOENT;
|
||||||
import static android.system.OsConstants.EOPNOTSUPP;
|
import static android.system.OsConstants.EOPNOTSUPP;
|
||||||
|
|
||||||
@@ -55,6 +56,11 @@ public class BpfNetMaps {
|
|||||||
private static final boolean USE_NETD = !SdkLevel.isAtLeastT();
|
private static final boolean USE_NETD = !SdkLevel.isAtLeastT();
|
||||||
private static boolean sInitialized = false;
|
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 =
|
private static final String CONFIGURATION_MAP_PATH =
|
||||||
"/sys/fs/bpf/netd_shared/map_netd_configuration_map";
|
"/sys/fs/bpf/netd_shared/map_netd_configuration_map";
|
||||||
private static final U32 UID_RULES_CONFIGURATION_KEY = new U32(0);
|
private static final U32 UID_RULES_CONFIGURATION_KEY = new U32(0);
|
||||||
@@ -152,7 +158,7 @@ public class BpfNetMaps {
|
|||||||
public long getMatchByFirewallChain(final int chain) {
|
public long getMatchByFirewallChain(final int chain) {
|
||||||
final long match = FIREWALL_CHAIN_TO_MATCH.get(chain, NO_MATCH);
|
final long match = FIREWALL_CHAIN_TO_MATCH.get(chain, NO_MATCH);
|
||||||
if (match == NO_MATCH) {
|
if (match == NO_MATCH) {
|
||||||
throw new IllegalArgumentException("Invalid firewall chain: " + chain);
|
throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain);
|
||||||
}
|
}
|
||||||
return match;
|
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
|
* Add naughty app bandwidth rule for specific app
|
||||||
*
|
*
|
||||||
@@ -216,12 +228,29 @@ public class BpfNetMaps {
|
|||||||
*
|
*
|
||||||
* @param childChain target chain to enable
|
* @param childChain target chain to enable
|
||||||
* @param enable whether to enable or disable child chain.
|
* @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
|
* @throws ServiceSpecificException in case of failure, with an error code indicating the
|
||||||
* cause of the failure.
|
* cause of the failure.
|
||||||
*/
|
*/
|
||||||
public void setChildChain(final int childChain, final boolean enable) {
|
public void setChildChain(final int childChain, final boolean enable) {
|
||||||
final int err = native_setChildChain(childChain, enable);
|
throwIfUseNetd("setChildChain is not available on pre-T devices");
|
||||||
maybeThrow(err, "Unable to set child chain");
|
|
||||||
|
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
|
* @param childChain target chain
|
||||||
* @return {@code true} if chain is enabled, {@code false} if chain is not enabled.
|
* @return {@code true} if chain is enabled, {@code false} if chain is not enabled.
|
||||||
* @throws UnsupportedOperationException if called on pre-T devices.
|
* @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
|
* @throws ServiceSpecificException in case of failure, with an error code indicating the
|
||||||
* cause of the failure.
|
* cause of the failure.
|
||||||
*/
|
*/
|
||||||
public boolean getChainEnabled(final int childChain) {
|
public boolean getChainEnabled(final int childChain) {
|
||||||
if (USE_NETD) {
|
throwIfUseNetd("getChainEnabled is not available on pre-T devices");
|
||||||
throw new UnsupportedOperationException("getChainEnabled is not available on pre-T"
|
|
||||||
+ " devices");
|
|
||||||
}
|
|
||||||
|
|
||||||
final long match = getMatchByFirewallChain(childChain);
|
final long match = getMatchByFirewallChain(childChain);
|
||||||
try {
|
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.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
|
||||||
import static android.net.INetd.PERMISSION_INTERNET;
|
import static android.net.INetd.PERMISSION_INTERNET;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertThrows;
|
import static org.junit.Assert.assertThrows;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@@ -168,7 +169,7 @@ public final class BpfNetMapsTest {
|
|||||||
@Test
|
@Test
|
||||||
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||||
public void testGetChainEnabledInvalidChain() {
|
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(-1 /* childChain */));
|
||||||
assertThrows(expected, () -> mBpfNetMaps.getChainEnabled(1000 /* childChain */));
|
assertThrows(expected, () -> mBpfNetMaps.getChainEnabled(1000 /* childChain */));
|
||||||
}
|
}
|
||||||
@@ -187,4 +188,81 @@ public final class BpfNetMapsTest {
|
|||||||
assertThrows(UnsupportedOperationException.class,
|
assertThrows(UnsupportedOperationException.class,
|
||||||
() -> mBpfNetMaps.getChainEnabled(FIREWALL_CHAIN_DOZABLE));
|
() -> 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