Add firewall chains for HAPPY_BOX and user/admin PENALTY_BOX

Follow up CLs will update CS to generate blocked reason from bpf map
instead of asking NPMS.

However, one issue is NPMS set PENALTY_BOX for
BLOCKED_METERED_REASON_USER_RESTRICTED and
BLOCKED_METERED_REASON_ADMIN_DISABLED without telling the reason.
So, CS can not know the reason of PENALTY_BOX.

This CL add new firewall chain and match to distinguish reasons.
NPMS must call setUidFirewallRule with
FIREWALL_CHAIN_METERED_DENY_USER or FIREWALL_CHAIN_METERED_DENY_ADMIN
based on the reason so that CS can know the reason of restriction.

Bug: 332628891
Test: atest com.android.cts.net.HostsideRestrictBackgroundNetworkTests
Change-Id: Ia4ad4bdb345abc22c782630e828edfad2452db36
This commit is contained in:
Motomu Utsumi 2024-04-02 18:29:08 +09:00
commit 11d3345daa
15 changed files with 300 additions and 307 deletions

View file

@ -69,9 +69,10 @@ base::Result<bool> DnsBpfHelper::isUidNetworkingBlocked(uid_t uid, bool metered)
// state, making it a trustworthy source. Since this library primarily serves DNS resolvers,
// relying solely on V+ data prevents erroneous blocking of DNS queries.
if (android::modules::sdklevel::IsAtLeastV() && metered) {
// The background data setting (PENALTY_BOX_MATCH) and unrestricted data usage setting
// (HAPPY_BOX_MATCH) for individual apps override the system wide Data Saver setting.
if (uidRules & PENALTY_BOX_MATCH) return true;
// The background data setting (PENALTY_BOX_USER_MATCH, PENALTY_BOX_ADMIN_MATCH) and
// unrestricted data usage setting (HAPPY_BOX_MATCH) for individual apps override the system
// wide Data Saver setting.
if (uidRules & (PENALTY_BOX_USER_MATCH | PENALTY_BOX_ADMIN_MATCH)) return true;
if (uidRules & HAPPY_BOX_MATCH) return false;
auto dataSaverSetting = mDataSaverEnabledMap.readValue(DATA_SAVER_ENABLED_KEY);

View file

@ -158,23 +158,33 @@ TEST_F(DnsBpfHelperTest, IsUidNetworkingBlocked_metered) {
}
} testConfigs[]{
// clang-format off
// enabledRules, dataSaverEnabled, uidRules, blocked
{NO_MATCH, false, NO_MATCH, false},
{NO_MATCH, false, PENALTY_BOX_MATCH, true},
{NO_MATCH, false, HAPPY_BOX_MATCH, false},
{NO_MATCH, false, PENALTY_BOX_MATCH|HAPPY_BOX_MATCH, true},
{NO_MATCH, true, NO_MATCH, true},
{NO_MATCH, true, PENALTY_BOX_MATCH, true},
{NO_MATCH, true, HAPPY_BOX_MATCH, false},
{NO_MATCH, true, PENALTY_BOX_MATCH|HAPPY_BOX_MATCH, true},
{STANDBY_MATCH, false, STANDBY_MATCH, true},
{STANDBY_MATCH, false, STANDBY_MATCH|PENALTY_BOX_MATCH, true},
{STANDBY_MATCH, false, STANDBY_MATCH|HAPPY_BOX_MATCH, true},
{STANDBY_MATCH, false, STANDBY_MATCH|PENALTY_BOX_MATCH|HAPPY_BOX_MATCH, true},
{STANDBY_MATCH, true, STANDBY_MATCH, true},
{STANDBY_MATCH, true, STANDBY_MATCH|PENALTY_BOX_MATCH, true},
{STANDBY_MATCH, true, STANDBY_MATCH|HAPPY_BOX_MATCH, true},
{STANDBY_MATCH, true, STANDBY_MATCH|PENALTY_BOX_MATCH|HAPPY_BOX_MATCH, true},
// enabledRules, dataSaverEnabled, uidRules, blocked
{NO_MATCH, false, NO_MATCH, false},
{NO_MATCH, false, PENALTY_BOX_USER_MATCH, true},
{NO_MATCH, false, PENALTY_BOX_ADMIN_MATCH, true},
{NO_MATCH, false, PENALTY_BOX_USER_MATCH|PENALTY_BOX_ADMIN_MATCH, true},
{NO_MATCH, false, HAPPY_BOX_MATCH, false},
{NO_MATCH, false, PENALTY_BOX_USER_MATCH|HAPPY_BOX_MATCH, true},
{NO_MATCH, false, PENALTY_BOX_ADMIN_MATCH|HAPPY_BOX_MATCH, true},
{NO_MATCH, true, NO_MATCH, true},
{NO_MATCH, true, PENALTY_BOX_USER_MATCH, true},
{NO_MATCH, true, PENALTY_BOX_ADMIN_MATCH, true},
{NO_MATCH, true, PENALTY_BOX_USER_MATCH|PENALTY_BOX_ADMIN_MATCH, true},
{NO_MATCH, true, HAPPY_BOX_MATCH, false},
{NO_MATCH, true, PENALTY_BOX_USER_MATCH|HAPPY_BOX_MATCH, true},
{NO_MATCH, true, PENALTY_BOX_ADMIN_MATCH|HAPPY_BOX_MATCH, true},
{STANDBY_MATCH, false, STANDBY_MATCH, true},
{STANDBY_MATCH, false, STANDBY_MATCH|PENALTY_BOX_USER_MATCH, true},
{STANDBY_MATCH, false, STANDBY_MATCH|PENALTY_BOX_ADMIN_MATCH, true},
{STANDBY_MATCH, false, STANDBY_MATCH|HAPPY_BOX_MATCH, true},
{STANDBY_MATCH, false, STANDBY_MATCH|PENALTY_BOX_USER_MATCH|HAPPY_BOX_MATCH, true},
{STANDBY_MATCH, false, STANDBY_MATCH|PENALTY_BOX_ADMIN_MATCH|HAPPY_BOX_MATCH, true},
{STANDBY_MATCH, true, STANDBY_MATCH, true},
{STANDBY_MATCH, true, STANDBY_MATCH|PENALTY_BOX_USER_MATCH, true},
{STANDBY_MATCH, true, STANDBY_MATCH|PENALTY_BOX_ADMIN_MATCH, true},
{STANDBY_MATCH, true, STANDBY_MATCH|HAPPY_BOX_MATCH, true},
{STANDBY_MATCH, true, STANDBY_MATCH|PENALTY_BOX_USER_MATCH|HAPPY_BOX_MATCH, true},
{STANDBY_MATCH, true, STANDBY_MATCH|PENALTY_BOX_ADMIN_MATCH|HAPPY_BOX_MATCH, true},
// clang-format on
};

View file

@ -644,7 +644,8 @@ DEFINE_XTBPF_PROG("skfilter/denylist/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_den
(struct __sk_buff* skb) {
uint32_t sock_uid = bpf_get_socket_uid(skb);
UidOwnerValue* denylistMatch = bpf_uid_owner_map_lookup_elem(&sock_uid);
if (denylistMatch) return denylistMatch->rule & PENALTY_BOX_MATCH ? BPF_MATCH : BPF_NOMATCH;
uint32_t penalty_box = PENALTY_BOX_USER_MATCH | PENALTY_BOX_ADMIN_MATCH;
if (denylistMatch) return denylistMatch->rule & penalty_box ? BPF_MATCH : BPF_NOMATCH;
return BPF_NOMATCH;
}

View file

@ -181,7 +181,7 @@ ASSERT_STRING_EQUAL(XT_BPF_DENYLIST_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilte
enum UidOwnerMatchType : uint32_t {
NO_MATCH = 0,
HAPPY_BOX_MATCH = (1 << 0),
PENALTY_BOX_MATCH = (1 << 1),
PENALTY_BOX_USER_MATCH = (1 << 1),
DOZABLE_MATCH = (1 << 2),
STANDBY_MATCH = (1 << 3),
POWERSAVE_MATCH = (1 << 4),
@ -192,7 +192,8 @@ enum UidOwnerMatchType : uint32_t {
OEM_DENY_1_MATCH = (1 << 9),
OEM_DENY_2_MATCH = (1 << 10),
OEM_DENY_3_MATCH = (1 << 11),
BACKGROUND_MATCH = (1 << 12)
BACKGROUND_MATCH = (1 << 12),
PENALTY_BOX_ADMIN_MATCH = (1 << 13),
};
// LINT.ThenChange(../framework/src/android/net/BpfNetMapsConstants.java)

View file

@ -56,6 +56,9 @@ package android.net {
field @FlaggedApi("com.android.net.flags.basic_background_restrictions_enabled") public static final int FIREWALL_CHAIN_BACKGROUND = 6; // 0x6
field public static final int FIREWALL_CHAIN_DOZABLE = 1; // 0x1
field public static final int FIREWALL_CHAIN_LOW_POWER_STANDBY = 5; // 0x5
field @FlaggedApi("com.android.net.flags.metered_network_firewall_chains") public static final int FIREWALL_CHAIN_METERED_ALLOW = 10; // 0xa
field @FlaggedApi("com.android.net.flags.metered_network_firewall_chains") public static final int FIREWALL_CHAIN_METERED_DENY_ADMIN = 12; // 0xc
field @FlaggedApi("com.android.net.flags.metered_network_firewall_chains") public static final int FIREWALL_CHAIN_METERED_DENY_USER = 11; // 0xb
field public static final int FIREWALL_CHAIN_OEM_DENY_1 = 7; // 0x7
field public static final int FIREWALL_CHAIN_OEM_DENY_2 = 8; // 0x8
field public static final int FIREWALL_CHAIN_OEM_DENY_3 = 9; // 0x9

View file

@ -19,6 +19,9 @@ package android.net;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3;
@ -67,7 +70,7 @@ public class BpfNetMapsConstants {
// LINT.IfChange(match_type)
public static final long NO_MATCH = 0;
public static final long HAPPY_BOX_MATCH = (1 << 0);
public static final long PENALTY_BOX_MATCH = (1 << 1);
public static final long PENALTY_BOX_USER_MATCH = (1 << 1);
public static final long DOZABLE_MATCH = (1 << 2);
public static final long STANDBY_MATCH = (1 << 3);
public static final long POWERSAVE_MATCH = (1 << 4);
@ -79,10 +82,11 @@ public class BpfNetMapsConstants {
public static final long OEM_DENY_2_MATCH = (1 << 10);
public static final long OEM_DENY_3_MATCH = (1 << 11);
public static final long BACKGROUND_MATCH = (1 << 12);
public static final long PENALTY_BOX_ADMIN_MATCH = (1 << 13);
public static final List<Pair<Long, String>> MATCH_LIST = Arrays.asList(
Pair.create(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH"),
Pair.create(PENALTY_BOX_MATCH, "PENALTY_BOX_MATCH"),
Pair.create(PENALTY_BOX_USER_MATCH, "PENALTY_BOX_USER_MATCH"),
Pair.create(DOZABLE_MATCH, "DOZABLE_MATCH"),
Pair.create(STANDBY_MATCH, "STANDBY_MATCH"),
Pair.create(POWERSAVE_MATCH, "POWERSAVE_MATCH"),
@ -93,11 +97,13 @@ public class BpfNetMapsConstants {
Pair.create(OEM_DENY_1_MATCH, "OEM_DENY_1_MATCH"),
Pair.create(OEM_DENY_2_MATCH, "OEM_DENY_2_MATCH"),
Pair.create(OEM_DENY_3_MATCH, "OEM_DENY_3_MATCH"),
Pair.create(BACKGROUND_MATCH, "BACKGROUND_MATCH")
Pair.create(BACKGROUND_MATCH, "BACKGROUND_MATCH"),
Pair.create(PENALTY_BOX_ADMIN_MATCH, "PENALTY_BOX_ADMIN_MATCH")
);
/**
* List of all firewall allow chains.
* List of all firewall allow chains that are applied to all networks regardless of meteredness
* See {@link #METERED_ALLOW_CHAINS} for allow chains that are only applied to metered networks.
*
* Allow chains mean the firewall denies all uids by default, uids must be explicitly allowed.
*/
@ -110,7 +116,8 @@ public class BpfNetMapsConstants {
);
/**
* List of all firewall deny chains.
* List of all firewall deny chains that are applied to all networks regardless of meteredness
* See {@link #METERED_DENY_CHAINS} for deny chains that are only applied to metered networks.
*
* Deny chains mean the firewall allows all uids by default, uids must be explicitly denied.
*/
@ -120,5 +127,24 @@ public class BpfNetMapsConstants {
FIREWALL_CHAIN_OEM_DENY_2,
FIREWALL_CHAIN_OEM_DENY_3
);
/**
* List of all firewall allow chains that are only applied to metered networks.
* See {@link #ALLOW_CHAINS} for allow chains that are applied to all networks regardless of
* meteredness.
*/
public static final List<Integer> METERED_ALLOW_CHAINS = List.of(
FIREWALL_CHAIN_METERED_ALLOW
);
/**
* List of all firewall deny chains that are only applied to metered networks.
* See {@link #DENY_CHAINS} for deny chains that are applied to all networks regardless of
* meteredness.
*/
public static final List<Integer> METERED_DENY_CHAINS = List.of(
FIREWALL_CHAIN_METERED_DENY_USER,
FIREWALL_CHAIN_METERED_DENY_ADMIN
);
// LINT.ThenChange(../../../../bpf_progs/netd.h)
}

View file

@ -25,11 +25,14 @@ import static android.net.BpfNetMapsConstants.DOZABLE_MATCH;
import static android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH;
import static android.net.BpfNetMapsConstants.LOW_POWER_STANDBY_MATCH;
import static android.net.BpfNetMapsConstants.MATCH_LIST;
import static android.net.BpfNetMapsConstants.METERED_ALLOW_CHAINS;
import static android.net.BpfNetMapsConstants.METERED_DENY_CHAINS;
import static android.net.BpfNetMapsConstants.NO_MATCH;
import static android.net.BpfNetMapsConstants.OEM_DENY_1_MATCH;
import static android.net.BpfNetMapsConstants.OEM_DENY_2_MATCH;
import static android.net.BpfNetMapsConstants.OEM_DENY_3_MATCH;
import static android.net.BpfNetMapsConstants.PENALTY_BOX_MATCH;
import static android.net.BpfNetMapsConstants.PENALTY_BOX_ADMIN_MATCH;
import static android.net.BpfNetMapsConstants.PENALTY_BOX_USER_MATCH;
import static android.net.BpfNetMapsConstants.POWERSAVE_MATCH;
import static android.net.BpfNetMapsConstants.RESTRICTED_MATCH;
import static android.net.BpfNetMapsConstants.STANDBY_MATCH;
@ -37,6 +40,9 @@ import static android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3;
@ -117,6 +123,12 @@ public class BpfNetMapsUtils {
return OEM_DENY_2_MATCH;
case FIREWALL_CHAIN_OEM_DENY_3:
return OEM_DENY_3_MATCH;
case FIREWALL_CHAIN_METERED_ALLOW:
return HAPPY_BOX_MATCH;
case FIREWALL_CHAIN_METERED_DENY_USER:
return PENALTY_BOX_USER_MATCH;
case FIREWALL_CHAIN_METERED_DENY_ADMIN:
return PENALTY_BOX_ADMIN_MATCH;
default:
throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain);
}
@ -129,9 +141,9 @@ public class BpfNetMapsUtils {
* DENYLIST means the firewall allows all by default, uids must be explicitly denied
*/
public static boolean isFirewallAllowList(final int chain) {
if (ALLOW_CHAINS.contains(chain)) {
if (ALLOW_CHAINS.contains(chain) || METERED_ALLOW_CHAINS.contains(chain)) {
return true;
} else if (DENY_CHAINS.contains(chain)) {
} else if (DENY_CHAINS.contains(chain) || METERED_DENY_CHAINS.contains(chain)) {
return false;
}
throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain);
@ -264,7 +276,7 @@ public class BpfNetMapsUtils {
}
if (!isNetworkMetered) return false;
if ((uidMatch & PENALTY_BOX_MATCH) != 0) return true;
if ((uidMatch & (PENALTY_BOX_USER_MATCH | PENALTY_BOX_ADMIN_MATCH)) != 0) return true;
if ((uidMatch & HAPPY_BOX_MATCH) != 0) return false;
return getDataSaverEnabled(dataSaverEnabledMap);
}

View file

@ -128,6 +128,8 @@ public class ConnectivityManager {
"com.android.net.flags.support_is_uid_networking_blocked";
static final String BASIC_BACKGROUND_RESTRICTIONS_ENABLED =
"com.android.net.flags.basic_background_restrictions_enabled";
static final String METERED_NETWORK_FIREWALL_CHAINS =
"com.android.net.flags.metered_network_firewall_chains";
}
/**
@ -1068,6 +1070,61 @@ public class ConnectivityManager {
@SystemApi(client = MODULE_LIBRARIES)
public static final int FIREWALL_CHAIN_OEM_DENY_3 = 9;
/**
* Firewall chain for allow list on metered networks
*
* UIDs added to this chain have access to metered networks, unless they're also in one of the
* denylist, {@link #FIREWALL_CHAIN_METERED_DENY_USER},
* {@link #FIREWALL_CHAIN_METERED_DENY_ADMIN}
*
* Note that this chain is used from a separate bpf program that is triggered by iptables and
* can not be controlled by {@link ConnectivityManager#setFirewallChainEnabled}.
*
* @hide
*/
// TODO: Merge this chain with data saver and support setFirewallChainEnabled
@FlaggedApi(Flags.METERED_NETWORK_FIREWALL_CHAINS)
@SystemApi(client = MODULE_LIBRARIES)
public static final int FIREWALL_CHAIN_METERED_ALLOW = 10;
/**
* Firewall chain for user-set restrictions on metered networks
*
* UIDs added to this chain do not have access to metered networks.
* UIDs should be added to this chain based on user settings.
* To restrict metered network based on admin configuration (e.g. enterprise policies),
* {@link #FIREWALL_CHAIN_METERED_DENY_ADMIN} should be used.
* This chain corresponds to {@link #BLOCKED_METERED_REASON_USER_RESTRICTED}
*
* Note that this chain is used from a separate bpf program that is triggered by iptables and
* can not be controlled by {@link ConnectivityManager#setFirewallChainEnabled}.
*
* @hide
*/
// TODO: Support setFirewallChainEnabled to control this chain
@FlaggedApi(Flags.METERED_NETWORK_FIREWALL_CHAINS)
@SystemApi(client = MODULE_LIBRARIES)
public static final int FIREWALL_CHAIN_METERED_DENY_USER = 11;
/**
* Firewall chain for admin-set restrictions on metered networks
*
* UIDs added to this chain do not have access to metered networks.
* UIDs should be added to this chain based on admin configuration (e.g. enterprise policies).
* To restrict metered network based on user settings, {@link #FIREWALL_CHAIN_METERED_DENY_USER}
* should be used.
* This chain corresponds to {@link #BLOCKED_METERED_REASON_ADMIN_DISABLED}
*
* Note that this chain is used from a separate bpf program that is triggered by iptables and
* can not be controlled by {@link ConnectivityManager#setFirewallChainEnabled}.
*
* @hide
*/
// TODO: Support setFirewallChainEnabled to control this chain
@FlaggedApi(Flags.METERED_NETWORK_FIREWALL_CHAINS)
@SystemApi(client = MODULE_LIBRARIES)
public static final int FIREWALL_CHAIN_METERED_DENY_ADMIN = 12;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = false, prefix = "FIREWALL_CHAIN_", value = {
@ -1079,7 +1136,10 @@ public class ConnectivityManager {
FIREWALL_CHAIN_BACKGROUND,
FIREWALL_CHAIN_OEM_DENY_1,
FIREWALL_CHAIN_OEM_DENY_2,
FIREWALL_CHAIN_OEM_DENY_3
FIREWALL_CHAIN_OEM_DENY_3,
FIREWALL_CHAIN_METERED_ALLOW,
FIREWALL_CHAIN_METERED_DENY_USER,
FIREWALL_CHAIN_METERED_DENY_ADMIN
})
public @interface FirewallChain {}
@ -6065,7 +6125,7 @@ public class ConnectivityManager {
})
public void addUidToMeteredNetworkAllowList(final int uid) {
try {
mService.updateMeteredNetworkAllowList(uid, true /* add */);
mService.setUidFirewallRule(FIREWALL_CHAIN_METERED_ALLOW, uid, FIREWALL_RULE_ALLOW);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@ -6088,7 +6148,7 @@ public class ConnectivityManager {
})
public void removeUidFromMeteredNetworkAllowList(final int uid) {
try {
mService.updateMeteredNetworkAllowList(uid, false /* remove */);
mService.setUidFirewallRule(FIREWALL_CHAIN_METERED_ALLOW, uid, FIREWALL_RULE_DENY);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@ -6098,10 +6158,17 @@ public class ConnectivityManager {
* Adds the specified UID to the list of UIDs that are not allowed to use background data on
* metered networks. Takes precedence over {@link #addUidToMeteredNetworkAllowList}.
*
* On V+, {@link #setUidFirewallRule} should be used with
* {@link #FIREWALL_CHAIN_METERED_DENY_USER} or {@link #FIREWALL_CHAIN_METERED_DENY_ADMIN}
* based on the reason so that users can receive {@link #BLOCKED_METERED_REASON_USER_RESTRICTED}
* or {@link #BLOCKED_METERED_REASON_ADMIN_DISABLED}, respectively.
* This API always uses {@link #FIREWALL_CHAIN_METERED_DENY_USER}.
*
* @param uid uid of target app
* @throws IllegalStateException if updating deny list failed.
* @hide
*/
// TODO(b/332649177): Deprecate this API after V
@SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_SETTINGS,
@ -6110,7 +6177,7 @@ public class ConnectivityManager {
})
public void addUidToMeteredNetworkDenyList(final int uid) {
try {
mService.updateMeteredNetworkDenyList(uid, true /* add */);
mService.setUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_USER, uid, FIREWALL_RULE_DENY);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@ -6121,10 +6188,17 @@ public class ConnectivityManager {
* networks if background data is not restricted. The deny list takes precedence over the
* allow list.
*
* On V+, {@link #setUidFirewallRule} should be used with
* {@link #FIREWALL_CHAIN_METERED_DENY_USER} or {@link #FIREWALL_CHAIN_METERED_DENY_ADMIN}
* based on the reason so that users can receive {@link #BLOCKED_METERED_REASON_USER_RESTRICTED}
* or {@link #BLOCKED_METERED_REASON_ADMIN_DISABLED}, respectively.
* This API always uses {@link #FIREWALL_CHAIN_METERED_DENY_USER}.
*
* @param uid uid of target app
* @throws IllegalStateException if updating deny list failed.
* @hide
*/
// TODO(b/332649177): Deprecate this API after V
@SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_SETTINGS,
@ -6133,7 +6207,7 @@ public class ConnectivityManager {
})
public void removeUidFromMeteredNetworkDenyList(final int uid) {
try {
mService.updateMeteredNetworkDenyList(uid, false /* remove */);
mService.setUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_USER, uid, FIREWALL_RULE_ALLOW);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@ -6191,6 +6265,10 @@ public class ConnectivityManager {
/**
* Enables or disables the specified firewall chain.
*
* Note that metered firewall chains can not be controlled by this API.
* See {@link #FIREWALL_CHAIN_METERED_ALLOW}, {@link #FIREWALL_CHAIN_METERED_DENY_USER}, and
* {@link #FIREWALL_CHAIN_METERED_DENY_ADMIN} for more detail.
*
* @param chain target chain.
* @param enable whether the chain should be enabled.
* @throws UnsupportedOperationException if called on pre-T devices.

View file

@ -242,10 +242,6 @@ interface IConnectivityManager
void setDataSaverEnabled(boolean enable);
void updateMeteredNetworkAllowList(int uid, boolean add);
void updateMeteredNetworkDenyList(int uid, boolean add);
void setUidFirewallRule(int chain, int uid, int rule);
int getUidFirewallRule(int chain, int uid);

View file

@ -23,11 +23,9 @@ import static android.net.BpfNetMapsConstants.DATA_SAVER_DISABLED;
import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED;
import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_KEY;
import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_MAP_PATH;
import static android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH;
import static android.net.BpfNetMapsConstants.IIF_MATCH;
import static android.net.BpfNetMapsConstants.INGRESS_DISCARD_MAP_PATH;
import static android.net.BpfNetMapsConstants.LOCKDOWN_VPN_MATCH;
import static android.net.BpfNetMapsConstants.PENALTY_BOX_MATCH;
import static android.net.BpfNetMapsConstants.UID_OWNER_MAP_PATH;
import static android.net.BpfNetMapsConstants.UID_PERMISSION_MAP_PATH;
import static android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY;
@ -445,62 +443,6 @@ public class BpfNetMaps {
addRule(uid, match, 0 /* iif */, caller);
}
/**
* Add naughty app bandwidth rule for specific app
*
* @param uid uid of target app
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public void addNaughtyApp(final int uid) {
throwIfPreT("addNaughtyApp is not available on pre-T devices");
addRule(uid, PENALTY_BOX_MATCH, "addNaughtyApp");
}
/**
* Remove naughty app bandwidth rule for specific app
*
* @param uid uid of target app
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public void removeNaughtyApp(final int uid) {
throwIfPreT("removeNaughtyApp is not available on pre-T devices");
removeRule(uid, PENALTY_BOX_MATCH, "removeNaughtyApp");
}
/**
* Add nice app bandwidth rule for specific app
*
* @param uid uid of target app
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public void addNiceApp(final int uid) {
throwIfPreT("addNiceApp is not available on pre-T devices");
addRule(uid, HAPPY_BOX_MATCH, "addNiceApp");
}
/**
* Remove nice app bandwidth rule for specific app
*
* @param uid uid of target app
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public void removeNiceApp(final int uid) {
throwIfPreT("removeNiceApp is not available on pre-T devices");
removeRule(uid, HAPPY_BOX_MATCH, "removeNiceApp");
}
/**
* Set target firewall child chain
*

View file

@ -24,6 +24,8 @@ import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.FEATURE_WIFI;
import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.BpfNetMapsConstants.METERED_ALLOW_CHAINS;
import static android.net.BpfNetMapsConstants.METERED_DENY_CHAINS;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_VALIDATION_RESULT;
@ -13474,36 +13476,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
@Override
public void updateMeteredNetworkAllowList(final int uid, final boolean add) {
enforceNetworkStackOrSettingsPermission();
try {
if (add) {
mBpfNetMaps.addNiceApp(uid);
} else {
mBpfNetMaps.removeNiceApp(uid);
}
} catch (ServiceSpecificException e) {
throw new IllegalStateException(e);
}
}
@Override
public void updateMeteredNetworkDenyList(final int uid, final boolean add) {
enforceNetworkStackOrSettingsPermission();
try {
if (add) {
mBpfNetMaps.addNaughtyApp(uid);
} else {
mBpfNetMaps.removeNaughtyApp(uid);
}
} catch (ServiceSpecificException e) {
throw new IllegalStateException(e);
}
}
private int setPackageFirewallRule(final int chain, final String packageName, final int rule)
throws PackageManager.NameNotFoundException {
final PackageManager pm = mContext.getPackageManager();
@ -13563,6 +13535,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
case ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1:
case ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2:
case ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3:
case ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER:
case ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN:
defaultRule = FIREWALL_RULE_ALLOW;
break;
case ConnectivityManager.FIREWALL_CHAIN_DOZABLE:
@ -13570,6 +13544,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
case ConnectivityManager.FIREWALL_CHAIN_RESTRICTED:
case ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY:
case ConnectivityManager.FIREWALL_CHAIN_BACKGROUND:
case ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW:
defaultRule = FIREWALL_RULE_DENY;
break;
default:
@ -13606,6 +13581,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
+ " the feature is disabled.");
return;
}
if (METERED_ALLOW_CHAINS.contains(chain) || METERED_DENY_CHAINS.contains(chain)) {
// Metered chains are used from a separate bpf program that is triggered by iptables
// and can not be controlled by setFirewallChainEnabled.
throw new UnsupportedOperationException(
"Chain (" + chain + ") can not be controlled by setFirewallChainEnabled");
}
try {
mBpfNetMaps.setChildChain(chain, enable);
@ -13626,6 +13607,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
public boolean getFirewallChainEnabled(final int chain) {
enforceNetworkStackOrSettingsPermission();
if (METERED_ALLOW_CHAINS.contains(chain) || METERED_DENY_CHAINS.contains(chain)) {
// Metered chains are used from a separate bpf program that is triggered by iptables
// and can not be controlled by setFirewallChainEnabled.
throw new UnsupportedOperationException(
"getFirewallChainEnabled can not return status of chain (" + chain + ")");
}
return mBpfNetMaps.isChainEnabled(chain);
}

View file

@ -21,7 +21,8 @@ import android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED
import android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_KEY
import android.net.BpfNetMapsConstants.DOZABLE_MATCH
import android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH
import android.net.BpfNetMapsConstants.PENALTY_BOX_MATCH
import android.net.BpfNetMapsConstants.PENALTY_BOX_ADMIN_MATCH
import android.net.BpfNetMapsConstants.PENALTY_BOX_USER_MATCH
import android.net.BpfNetMapsConstants.STANDBY_MATCH
import android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY
import android.net.BpfNetMapsUtils.getMatchByFirewallChain
@ -48,9 +49,9 @@ private const val TEST_UID2 = TEST_UID1 + 1
private const val TEST_UID3 = TEST_UID2 + 1
private const val NO_IIF = 0
// pre-T devices does not support Bpf.
// NetworkStack can not use this before U due to b/326143935
@RunWith(DevSdkIgnoreRunner::class)
@IgnoreUpTo(VERSION_CODES.S_V2)
@IgnoreUpTo(VERSION_CODES.TIRAMISU)
class NetworkStackBpfNetMapsTest {
@Rule
@JvmField
@ -102,14 +103,18 @@ class NetworkStackBpfNetMapsTest {
}
// Verify the size matches, this also verifies no common item in allow and deny chains.
assertEquals(
BpfNetMapsConstants.ALLOW_CHAINS.size +
BpfNetMapsConstants.DENY_CHAINS.size,
BpfNetMapsConstants.ALLOW_CHAINS.size +
BpfNetMapsConstants.DENY_CHAINS.size +
BpfNetMapsConstants.METERED_ALLOW_CHAINS.size +
BpfNetMapsConstants.METERED_DENY_CHAINS.size,
declaredChains.size
)
declaredChains.forEach {
assertTrue(
BpfNetMapsConstants.ALLOW_CHAINS.contains(it.get(null)) ||
BpfNetMapsConstants.DENY_CHAINS.contains(it.get(null))
BpfNetMapsConstants.ALLOW_CHAINS.contains(it.get(null)) ||
BpfNetMapsConstants.METERED_ALLOW_CHAINS.contains(it.get(null)) ||
BpfNetMapsConstants.DENY_CHAINS.contains(it.get(null)) ||
BpfNetMapsConstants.METERED_DENY_CHAINS.contains(it.get(null))
)
}
}
@ -190,7 +195,16 @@ class NetworkStackBpfNetMapsTest {
// Add uid1 to penalty box, verify the network is blocked for uid1, while uid2 is not
// affected.
testUidOwnerMap.updateEntry(S32(TEST_UID1), UidOwnerValue(NO_IIF, PENALTY_BOX_MATCH))
testUidOwnerMap.updateEntry(S32(TEST_UID1), UidOwnerValue(NO_IIF, PENALTY_BOX_USER_MATCH))
assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true))
assertFalse(isUidNetworkingBlocked(TEST_UID2, metered = true))
testUidOwnerMap.updateEntry(S32(TEST_UID1), UidOwnerValue(NO_IIF, PENALTY_BOX_ADMIN_MATCH))
assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true))
assertFalse(isUidNetworkingBlocked(TEST_UID2, metered = true))
testUidOwnerMap.updateEntry(
S32(TEST_UID1),
UidOwnerValue(NO_IIF, PENALTY_BOX_USER_MATCH or PENALTY_BOX_ADMIN_MATCH)
)
assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true))
assertFalse(isUidNetworkingBlocked(TEST_UID2, metered = true))
@ -206,7 +220,14 @@ class NetworkStackBpfNetMapsTest {
// priority.
testUidOwnerMap.updateEntry(
S32(TEST_UID1),
UidOwnerValue(NO_IIF, PENALTY_BOX_MATCH or HAPPY_BOX_MATCH)
UidOwnerValue(NO_IIF, PENALTY_BOX_USER_MATCH or HAPPY_BOX_MATCH)
)
assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true))
assertTrue(isUidNetworkingBlocked(TEST_UID2, metered = true))
assertFalse(isUidNetworkingBlocked(TEST_UID3, metered = true))
testUidOwnerMap.updateEntry(
S32(TEST_UID1),
UidOwnerValue(NO_IIF, PENALTY_BOX_ADMIN_MATCH or HAPPY_BOX_MATCH)
)
assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true))
assertTrue(isUidNetworkingBlocked(TEST_UID2, metered = true))
@ -240,7 +261,7 @@ class NetworkStackBpfNetMapsTest {
for (uid in FIRST_APPLICATION_UID - 5..FIRST_APPLICATION_UID + 5) {
// system uid is not blocked regardless of firewall chains
val expectBlocked = uid >= FIRST_APPLICATION_UID
testUidOwnerMap.updateEntry(S32(uid), UidOwnerValue(NO_IIF, PENALTY_BOX_MATCH))
testUidOwnerMap.updateEntry(S32(uid), UidOwnerValue(NO_IIF, PENALTY_BOX_USER_MATCH))
assertEquals(
expectBlocked,
isUidNetworkingBlocked(uid, metered = true),

View file

@ -31,13 +31,17 @@ import static android.net.BpfNetMapsConstants.NO_MATCH;
import static android.net.BpfNetMapsConstants.OEM_DENY_1_MATCH;
import static android.net.BpfNetMapsConstants.OEM_DENY_2_MATCH;
import static android.net.BpfNetMapsConstants.OEM_DENY_3_MATCH;
import static android.net.BpfNetMapsConstants.PENALTY_BOX_MATCH;
import static android.net.BpfNetMapsConstants.PENALTY_BOX_ADMIN_MATCH;
import static android.net.BpfNetMapsConstants.PENALTY_BOX_USER_MATCH;
import static android.net.BpfNetMapsConstants.POWERSAVE_MATCH;
import static android.net.BpfNetMapsConstants.RESTRICTED_MATCH;
import static android.net.BpfNetMapsConstants.STANDBY_MATCH;
import static android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3;
@ -334,146 +338,6 @@ public final class BpfNetMapsTest {
}
}
private void doTestRemoveNaughtyApp(final int iif, final long match) throws Exception {
mUidOwnerMap.updateEntry(new S32(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));
}
private void doTestAddNaughtyApp(final int iif, final long match) throws Exception {
if (match != NO_MATCH) {
mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match));
}
mBpfNetMaps.addNaughtyApp(TEST_UID);
checkUidOwnerValue(TEST_UID, iif, match | PENALTY_BOX_MATCH);
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
public void testAddNaughtyApp() throws Exception {
doTestAddNaughtyApp(NO_IIF, NO_MATCH);
// Other matches are enabled
doTestAddNaughtyApp(NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH);
// IIF_MATCH is enabled
doTestAddNaughtyApp(TEST_IF_INDEX, IIF_MATCH);
// PENALTY_BOX_MATCH is already enabled
doTestAddNaughtyApp(NO_IIF, PENALTY_BOX_MATCH | DOZABLE_MATCH);
}
@Test
@IgnoreAfter(Build.VERSION_CODES.S_V2)
public void testAddNaughtyAppBeforeT() {
assertThrows(UnsupportedOperationException.class,
() -> mBpfNetMaps.addNaughtyApp(TEST_UID));
}
private void doTestRemoveNiceApp(final int iif, final long match) throws Exception {
mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match));
mBpfNetMaps.removeNiceApp(TEST_UID);
checkUidOwnerValue(TEST_UID, iif, match & ~HAPPY_BOX_MATCH);
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
public void testRemoveNiceApp() throws Exception {
doTestRemoveNiceApp(NO_IIF, HAPPY_BOX_MATCH);
// HAPPY_BOX_MATCH with other matches
doTestRemoveNiceApp(NO_IIF, HAPPY_BOX_MATCH | DOZABLE_MATCH | POWERSAVE_MATCH);
// HAPPY_BOX_MATCH with IIF_MATCH
doTestRemoveNiceApp(TEST_IF_INDEX, HAPPY_BOX_MATCH | IIF_MATCH);
// HAPPY_BOX_MATCH is not enabled
doTestRemoveNiceApp(NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH);
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
public void testRemoveNiceAppMissingUid() {
// UidOwnerMap does not have entry for TEST_UID
assertThrows(ServiceSpecificException.class,
() -> mBpfNetMaps.removeNiceApp(TEST_UID));
}
@Test
@IgnoreAfter(Build.VERSION_CODES.S_V2)
public void testRemoveNiceAppBeforeT() {
assertThrows(UnsupportedOperationException.class,
() -> mBpfNetMaps.removeNiceApp(TEST_UID));
}
private void doTestAddNiceApp(final int iif, final long match) throws Exception {
if (match != NO_MATCH) {
mUidOwnerMap.updateEntry(new S32(TEST_UID), new UidOwnerValue(iif, match));
}
mBpfNetMaps.addNiceApp(TEST_UID);
checkUidOwnerValue(TEST_UID, iif, match | HAPPY_BOX_MATCH);
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
public void testAddNiceApp() throws Exception {
doTestAddNiceApp(NO_IIF, NO_MATCH);
// Other matches are enabled
doTestAddNiceApp(NO_IIF, DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH);
// IIF_MATCH is enabled
doTestAddNiceApp(TEST_IF_INDEX, IIF_MATCH);
// HAPPY_BOX_MATCH is already enabled
doTestAddNiceApp(NO_IIF, HAPPY_BOX_MATCH | DOZABLE_MATCH);
}
@Test
@IgnoreAfter(Build.VERSION_CODES.S_V2)
public void testAddNiceAppBeforeT() {
assertThrows(UnsupportedOperationException.class,
() -> mBpfNetMaps.addNiceApp(TEST_UID));
}
private void doTestUpdateUidLockdownRule(final int iif, final long match, final boolean add)
throws Exception {
if (match != NO_MATCH) {
@ -658,6 +522,9 @@ public final class BpfNetMapsTest {
doTestSetUidRule(FIREWALL_CHAIN_OEM_DENY_1);
doTestSetUidRule(FIREWALL_CHAIN_OEM_DENY_2);
doTestSetUidRule(FIREWALL_CHAIN_OEM_DENY_3);
doTestSetUidRule(FIREWALL_CHAIN_METERED_ALLOW);
doTestSetUidRule(FIREWALL_CHAIN_METERED_DENY_USER);
doTestSetUidRule(FIREWALL_CHAIN_METERED_DENY_ADMIN);
}
@Test
@ -1079,7 +946,7 @@ public final class BpfNetMapsTest {
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
public void testDumpUidOwnerMap() throws Exception {
doTestDumpUidOwnerMap(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH");
doTestDumpUidOwnerMap(PENALTY_BOX_MATCH, "PENALTY_BOX_MATCH");
doTestDumpUidOwnerMap(PENALTY_BOX_USER_MATCH, "PENALTY_BOX_USER_MATCH");
doTestDumpUidOwnerMap(DOZABLE_MATCH, "DOZABLE_MATCH");
doTestDumpUidOwnerMap(STANDBY_MATCH, "STANDBY_MATCH");
doTestDumpUidOwnerMap(POWERSAVE_MATCH, "POWERSAVE_MATCH");
@ -1089,6 +956,7 @@ public final class BpfNetMapsTest {
doTestDumpUidOwnerMap(OEM_DENY_1_MATCH, "OEM_DENY_1_MATCH");
doTestDumpUidOwnerMap(OEM_DENY_2_MATCH, "OEM_DENY_2_MATCH");
doTestDumpUidOwnerMap(OEM_DENY_3_MATCH, "OEM_DENY_3_MATCH");
doTestDumpUidOwnerMap(PENALTY_BOX_ADMIN_MATCH, "PENALTY_BOX_ADMIN_MATCH");
doTestDumpUidOwnerMap(HAPPY_BOX_MATCH | POWERSAVE_MATCH,
"HAPPY_BOX_MATCH POWERSAVE_MATCH");
@ -1137,7 +1005,6 @@ public final class BpfNetMapsTest {
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
public void testDumpUidOwnerMapConfig() throws Exception {
doTestDumpOwnerMatchConfig(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH");
doTestDumpOwnerMatchConfig(PENALTY_BOX_MATCH, "PENALTY_BOX_MATCH");
doTestDumpOwnerMatchConfig(DOZABLE_MATCH, "DOZABLE_MATCH");
doTestDumpOwnerMatchConfig(STANDBY_MATCH, "STANDBY_MATCH");
doTestDumpOwnerMatchConfig(POWERSAVE_MATCH, "POWERSAVE_MATCH");

View file

@ -63,6 +63,9 @@ import static android.net.ConnectivityManager.EXTRA_REALTIME_NS;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3;
@ -10497,6 +10500,9 @@ public class ConnectivityServiceTest {
doTestSetUidFirewallRule(FIREWALL_CHAIN_OEM_DENY_1, FIREWALL_RULE_ALLOW);
doTestSetUidFirewallRule(FIREWALL_CHAIN_OEM_DENY_2, FIREWALL_RULE_ALLOW);
doTestSetUidFirewallRule(FIREWALL_CHAIN_OEM_DENY_3, FIREWALL_RULE_ALLOW);
doTestSetUidFirewallRule(FIREWALL_CHAIN_METERED_ALLOW, FIREWALL_RULE_DENY);
doTestSetUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_USER, FIREWALL_RULE_ALLOW);
doTestSetUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_ADMIN, FIREWALL_RULE_ALLOW);
}
@Test @IgnoreUpTo(SC_V2)

View file

@ -16,7 +16,14 @@
package com.android.server
import android.net.ConnectivityManager
import android.net.BpfNetMapsConstants.METERED_ALLOW_CHAINS
import android.net.BpfNetMapsConstants.METERED_DENY_CHAINS
import android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND
import android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW
import android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER
import android.net.ConnectivityManager.FIREWALL_RULE_ALLOW
import android.net.ConnectivityManager.FIREWALL_RULE_DEFAULT
import android.net.ConnectivityManager.FIREWALL_RULE_DENY
import android.os.Build
import androidx.test.filters.SmallTest
import com.android.server.connectivity.ConnectivityFlags.BACKGROUND_FIREWALL_CHAIN
@ -24,6 +31,7 @@ import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.assertThrows
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@ -52,13 +60,13 @@ class CSFirewallChainTest : CSTest() {
@FeatureFlags(flags = [Flag(BACKGROUND_FIREWALL_CHAIN, true)])
@IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
fun setFirewallChainEnabled_backgroundChainEnabled_afterU() {
cm.setFirewallChainEnabled(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, true)
verify(bpfNetMaps).setChildChain(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, true)
cm.setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, true)
verify(bpfNetMaps).setChildChain(FIREWALL_CHAIN_BACKGROUND, true)
clearInvocations(bpfNetMaps)
cm.setFirewallChainEnabled(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, false)
verify(bpfNetMaps).setChildChain(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, false)
cm.setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, false)
verify(bpfNetMaps).setChildChain(FIREWALL_CHAIN_BACKGROUND, false)
}
@Test
@ -69,10 +77,10 @@ class CSFirewallChainTest : CSTest() {
}
private fun verifySetFirewallChainEnabledOnBackgroundDoesNothing() {
cm.setFirewallChainEnabled(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, true)
cm.setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, true)
verify(bpfNetMaps, never()).setChildChain(anyInt(), anyBoolean())
cm.setFirewallChainEnabled(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, false)
cm.setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, false)
verify(bpfNetMaps, never()).setChildChain(anyInt(), anyBoolean())
}
@ -88,8 +96,8 @@ class CSFirewallChainTest : CSTest() {
@IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
fun replaceFirewallChain_backgroundChainEnabled_afterU() {
val uids = intArrayOf(53, 42, 79)
cm.replaceFirewallChain(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uids)
verify(bpfNetMaps).replaceUidChain(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uids)
cm.replaceFirewallChain(FIREWALL_CHAIN_BACKGROUND, uids)
verify(bpfNetMaps).replaceUidChain(FIREWALL_CHAIN_BACKGROUND, uids)
}
@Test
@ -101,7 +109,7 @@ class CSFirewallChainTest : CSTest() {
private fun verifyReplaceFirewallChainOnBackgroundDoesNothing() {
val uids = intArrayOf(53, 42, 79)
cm.replaceFirewallChain(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uids)
cm.replaceFirewallChain(FIREWALL_CHAIN_BACKGROUND, uids)
verify(bpfNetMaps, never()).replaceUidChain(anyInt(), any(IntArray::class.java))
}
@ -118,24 +126,18 @@ class CSFirewallChainTest : CSTest() {
fun setUidFirewallRule_backgroundChainEnabled_afterU() {
val uid = 2345
cm.setUidFirewallRule(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uid,
ConnectivityManager.FIREWALL_RULE_DEFAULT)
verify(bpfNetMaps).setUidRule(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uid,
ConnectivityManager.FIREWALL_RULE_DENY)
cm.setUidFirewallRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_DEFAULT)
verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_DENY)
clearInvocations(bpfNetMaps)
cm.setUidFirewallRule(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uid,
ConnectivityManager.FIREWALL_RULE_DENY)
verify(bpfNetMaps).setUidRule(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uid,
ConnectivityManager.FIREWALL_RULE_DENY)
cm.setUidFirewallRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_DENY)
verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_DENY)
clearInvocations(bpfNetMaps)
cm.setUidFirewallRule(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uid,
ConnectivityManager.FIREWALL_RULE_ALLOW)
verify(bpfNetMaps).setUidRule(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uid,
ConnectivityManager.FIREWALL_RULE_ALLOW)
cm.setUidFirewallRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_ALLOW)
verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_BACKGROUND, uid, FIREWALL_RULE_ALLOW)
}
@Test
@ -148,10 +150,49 @@ class CSFirewallChainTest : CSTest() {
private fun verifySetUidFirewallRuleOnBackgroundDoesNothing() {
val uid = 2345
listOf(ConnectivityManager.FIREWALL_RULE_DEFAULT, ConnectivityManager.FIREWALL_RULE_ALLOW,
ConnectivityManager.FIREWALL_RULE_DENY).forEach { rule ->
cm.setUidFirewallRule(ConnectivityManager.FIREWALL_CHAIN_BACKGROUND, uid, rule)
listOf(FIREWALL_RULE_DEFAULT, FIREWALL_RULE_ALLOW, FIREWALL_RULE_DENY).forEach { rule ->
cm.setUidFirewallRule(FIREWALL_CHAIN_BACKGROUND, uid, rule)
verify(bpfNetMaps, never()).setUidRule(anyInt(), anyInt(), anyInt())
}
}
@Test
fun testSetFirewallChainEnabled_meteredChain() {
(METERED_ALLOW_CHAINS + METERED_DENY_CHAINS).forEach {
assertThrows(UnsupportedOperationException::class.java) {
cm.setFirewallChainEnabled(it, true)
}
assertThrows(UnsupportedOperationException::class.java) {
cm.setFirewallChainEnabled(it, false)
}
}
}
@Test
fun testAddUidToMeteredNetworkAllowList() {
val uid = 1001
cm.addUidToMeteredNetworkAllowList(uid)
verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_METERED_ALLOW, uid, FIREWALL_RULE_ALLOW)
}
@Test
fun testRemoveUidFromMeteredNetworkAllowList() {
val uid = 1001
cm.removeUidFromMeteredNetworkAllowList(uid)
verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_METERED_ALLOW, uid, FIREWALL_RULE_DENY)
}
@Test
fun testAddUidToMeteredNetworkDenyList() {
val uid = 1001
cm.addUidToMeteredNetworkDenyList(uid)
verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_METERED_DENY_USER, uid, FIREWALL_RULE_DENY)
}
@Test
fun testRemoveUidFromMeteredNetworkDenyList() {
val uid = 1001
cm.removeUidFromMeteredNetworkDenyList(uid)
verify(bpfNetMaps).setUidRule(FIREWALL_CHAIN_METERED_DENY_USER, uid, FIREWALL_RULE_ALLOW)
}
}