diff --git a/bpf/progs/netd.c b/bpf/progs/netd.c index b146e4539e..c943a64b52 100644 --- a/bpf/progs/netd.c +++ b/bpf/progs/netd.c @@ -460,6 +460,21 @@ static __always_inline inline bool ingress_should_discard(struct __sk_buff* skb, return true; // disallowed interface } +static __always_inline inline int bpf_owner_firewall_match(uint32_t uid) { + if (is_system_uid(uid)) return PASS; + + const BpfConfig enabledRules = getConfig(UID_RULES_CONFIGURATION_KEY); + const UidOwnerValue* uidEntry = bpf_uid_owner_map_lookup_elem(&uid); + const uint32_t uidRules = uidEntry ? uidEntry->rule : 0; + + if (enabledRules & (FIREWALL_DROP_IF_SET | FIREWALL_DROP_IF_UNSET) + & (uidRules ^ FIREWALL_DROP_IF_UNSET)) { + return DROP; + } + + return PASS; +} + static __always_inline inline int bpf_owner_match(struct __sk_buff* skb, uint32_t uid, const struct egress_bool egress, const struct kver_uint kver, @@ -756,15 +771,14 @@ DEFINE_XTBPF_PROG("skfilter/denylist/xtbpf", xt_bpf_denylist_prog) return XTBPF_NOMATCH; } -static __always_inline inline uint8_t get_app_permissions() { - uint64_t gid_uid = bpf_get_current_uid_gid(); +static __always_inline inline uint8_t get_app_permissions(uint32_t uid) { /* * A given app is guaranteed to have the same app ID in all the profiles in * which it is installed, and install permission is granted to app for all * user at install time so we only check the appId part of a request uid at * run time. See UserHandle#isSameApp for detail. */ - uint32_t appId = (gid_uid & 0xffffffff) % AID_USER_OFFSET; // == PER_USER_RANGE == 100000 + uint32_t appId = uid % AID_USER_OFFSET; // == PER_USER_RANGE == 100000 uint8_t* permissions = bpf_uid_permission_map_lookup_elem(&appId); // if UID not in map, then default to just INTERNET permission. return permissions ? *permissions : BPF_PERMISSION_INTERNET; @@ -772,7 +786,12 @@ static __always_inline inline uint8_t get_app_permissions() { DEFINE_NETD_BPF_PROG_KVER("cgroupsock/inet_create", inet_socket_create, KVER_4_14) (__unused struct bpf_sock* sk) { - return (get_app_permissions() & BPF_PERMISSION_INTERNET) ? BPF_ALLOW : BPF_DISALLOW; + uint64_t uid = bpf_get_current_uid_gid() & 0xffffffff; + if (get_app_permissions(uid) & BPF_PERMISSION_INTERNET) { + return bpf_owner_firewall_match(uid) == PASS ? BPF_ALLOW : BPF_DISALLOW; + } else { + return BPF_DISALLOW; + } } DEFINE_NETD_BPF_PROG_KVER("cgroupsockrelease/inet_release", inet_socket_release, KVER_5_10) diff --git a/bpf/progs/netd.h b/bpf/progs/netd.h index 8400679a2a..a643981b2c 100644 --- a/bpf/progs/netd.h +++ b/bpf/progs/netd.h @@ -274,6 +274,9 @@ STRUCT_SIZE(LocalNetAccessKey, 4 + 4 + 16 + 2 + 2); // 28 #define DROP_IF_UNSET (DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH \ | LOW_POWER_STANDBY_MATCH | BACKGROUND_MATCH) +#define FIREWALL_DROP_IF_SET (OEM_DENY_1_MATCH) +#define FIREWALL_DROP_IF_UNSET (RESTRICTED_MATCH) + // Warning: funky bit-wise arithmetic: in parallel, for all DROP_IF_SET/UNSET rules // check whether the rules are globally enabled, and if so whether the rules are // set/unset for the specific uid. DROP if that is the case for ANY of the rules.