netd.c - switch from is_4_19 to simply passing KVER(4, 19, 0) around
will make it easier to extend this for 5.4+ behaviour as well without having to introduce another is_5_4 boolean Bug: 263884894 Test: TreeHugger Signed-off-by: Maciej Żenczykowski <maze@google.com> Change-Id: Id4f6512d813dd460cb2b9a7ccb6a5f7b7e937575
This commit is contained in:
@@ -194,19 +194,38 @@ DEFINE_UPDATE_STATS(stats_map_A, StatsKey)
|
|||||||
DEFINE_UPDATE_STATS(stats_map_B, StatsKey)
|
DEFINE_UPDATE_STATS(stats_map_B, StatsKey)
|
||||||
|
|
||||||
// both of these return 0 on success or -EFAULT on failure (and zero out the buffer)
|
// both of these return 0 on success or -EFAULT on failure (and zero out the buffer)
|
||||||
static __always_inline inline int bpf_skb_load_bytes_net(const struct __sk_buff* skb, int off,
|
static __always_inline inline int bpf_skb_load_bytes_net(const struct __sk_buff* const skb,
|
||||||
void* to, int len, bool is_4_19) {
|
const int L3_off,
|
||||||
return is_4_19
|
void* const to,
|
||||||
? bpf_skb_load_bytes_relative(skb, off, to, len, BPF_HDR_START_NET)
|
const int len,
|
||||||
: bpf_skb_load_bytes(skb, off, to, len);
|
const unsigned kver) {
|
||||||
|
// 'kver' (here and throughout) is the compile time guaranteed minimum kernel version,
|
||||||
|
// ie. we're building (a version of) the bpf program for kver (or newer!) kernels.
|
||||||
|
//
|
||||||
|
// 4.19+ kernels support the 'bpf_skb_load_bytes_relative()' bpf helper function,
|
||||||
|
// so we can use it. On pre-4.19 kernels we cannot use the relative load helper,
|
||||||
|
// and thus will simply get things wrong if there's any L2 (ethernet) header in the skb.
|
||||||
|
//
|
||||||
|
// Luckily, for cellular traffic, there likely isn't any, as cell is usually 'rawip'.
|
||||||
|
//
|
||||||
|
// However, this does mean that wifi (and ethernet) on 4.14 is basically a lost cause:
|
||||||
|
// we'll be making decisions based on the *wrong* bytes (fetched from the wrong offset),
|
||||||
|
// because the 'L3_off' passed to bpf_skb_load_bytes() should be increased by l2_header_size,
|
||||||
|
// which for ethernet is 14 and not 0 like it is for rawip.
|
||||||
|
//
|
||||||
|
// For similar reasons this will fail with non-offloaded VLAN tags on < 4.19 kernels,
|
||||||
|
// since those extend the ethernet header from 14 to 18 bytes.
|
||||||
|
return kver >= KVER(4, 19, 0)
|
||||||
|
? bpf_skb_load_bytes_relative(skb, L3_off, to, len, BPF_HDR_START_NET)
|
||||||
|
: bpf_skb_load_bytes(skb, L3_off, to, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __always_inline inline bool skip_owner_match(struct __sk_buff* skb, bool is_4_19) {
|
static __always_inline inline bool skip_owner_match(struct __sk_buff* skb, const unsigned kver) {
|
||||||
uint32_t flag = 0;
|
uint32_t flag = 0;
|
||||||
if (skb->protocol == htons(ETH_P_IP)) {
|
if (skb->protocol == htons(ETH_P_IP)) {
|
||||||
uint8_t proto;
|
uint8_t proto;
|
||||||
// no need to check for success, proto will be zeroed if bpf_skb_load_bytes_net() fails
|
// no need to check for success, proto will be zeroed if bpf_skb_load_bytes_net() fails
|
||||||
(void)bpf_skb_load_bytes_net(skb, IP_PROTO_OFF, &proto, sizeof(proto), is_4_19);
|
(void)bpf_skb_load_bytes_net(skb, IP_PROTO_OFF, &proto, sizeof(proto), kver);
|
||||||
if (proto == IPPROTO_ESP) return true;
|
if (proto == IPPROTO_ESP) return true;
|
||||||
if (proto != IPPROTO_TCP) return false; // handles read failure above
|
if (proto != IPPROTO_TCP) return false; // handles read failure above
|
||||||
uint8_t ihl;
|
uint8_t ihl;
|
||||||
@@ -215,19 +234,19 @@ static __always_inline inline bool skip_owner_match(struct __sk_buff* skb, bool
|
|||||||
// (a little bit deeper in the packet in spite of ihl being zeroed) of the tcp flags
|
// (a little bit deeper in the packet in spite of ihl being zeroed) of the tcp flags
|
||||||
// field will also fail, and that failure we already handle correctly
|
// field will also fail, and that failure we already handle correctly
|
||||||
// (we also don't check that ihl in [0x45,0x4F] nor that ipv4 header checksum is correct)
|
// (we also don't check that ihl in [0x45,0x4F] nor that ipv4 header checksum is correct)
|
||||||
(void)bpf_skb_load_bytes_net(skb, IPPROTO_IHL_OFF, &ihl, sizeof(ihl), is_4_19);
|
(void)bpf_skb_load_bytes_net(skb, IPPROTO_IHL_OFF, &ihl, sizeof(ihl), kver);
|
||||||
// if the read below fails, we'll just assume no TCP flags are set, which is fine.
|
// if the read below fails, we'll just assume no TCP flags are set, which is fine.
|
||||||
(void)bpf_skb_load_bytes_net(skb, (ihl & 0xF) * 4 + TCP_FLAG32_OFF,
|
(void)bpf_skb_load_bytes_net(skb, (ihl & 0xF) * 4 + TCP_FLAG32_OFF,
|
||||||
&flag, sizeof(flag), is_4_19);
|
&flag, sizeof(flag), kver);
|
||||||
} else if (skb->protocol == htons(ETH_P_IPV6)) {
|
} else if (skb->protocol == htons(ETH_P_IPV6)) {
|
||||||
uint8_t proto;
|
uint8_t proto;
|
||||||
// no need to check for success, proto will be zeroed if bpf_skb_load_bytes_net() fails
|
// no need to check for success, proto will be zeroed if bpf_skb_load_bytes_net() fails
|
||||||
(void)bpf_skb_load_bytes_net(skb, IPV6_PROTO_OFF, &proto, sizeof(proto), is_4_19);
|
(void)bpf_skb_load_bytes_net(skb, IPV6_PROTO_OFF, &proto, sizeof(proto), kver);
|
||||||
if (proto == IPPROTO_ESP) return true;
|
if (proto == IPPROTO_ESP) return true;
|
||||||
if (proto != IPPROTO_TCP) return false; // handles read failure above
|
if (proto != IPPROTO_TCP) return false; // handles read failure above
|
||||||
// if the read below fails, we'll just assume no TCP flags are set, which is fine.
|
// if the read below fails, we'll just assume no TCP flags are set, which is fine.
|
||||||
(void)bpf_skb_load_bytes_net(skb, sizeof(struct ipv6hdr) + TCP_FLAG32_OFF,
|
(void)bpf_skb_load_bytes_net(skb, sizeof(struct ipv6hdr) + TCP_FLAG32_OFF,
|
||||||
&flag, sizeof(flag), is_4_19);
|
&flag, sizeof(flag), kver);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -250,8 +269,8 @@ static __always_inline inline BpfConfig getConfig(uint32_t configKey) {
|
|||||||
#define DROP_IF_UNSET (DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH | LOW_POWER_STANDBY_MATCH)
|
#define DROP_IF_UNSET (DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH | LOW_POWER_STANDBY_MATCH)
|
||||||
|
|
||||||
static __always_inline inline int bpf_owner_match(struct __sk_buff* skb, uint32_t uid,
|
static __always_inline inline int bpf_owner_match(struct __sk_buff* skb, uint32_t uid,
|
||||||
bool egress, bool is_4_19) {
|
bool egress, const unsigned kver) {
|
||||||
if (skip_owner_match(skb, is_4_19)) return PASS;
|
if (skip_owner_match(skb, kver)) return PASS;
|
||||||
|
|
||||||
if (is_system_uid(uid)) return PASS;
|
if (is_system_uid(uid)) return PASS;
|
||||||
|
|
||||||
@@ -294,7 +313,7 @@ static __always_inline inline void update_stats_with_config(struct __sk_buff* sk
|
|||||||
}
|
}
|
||||||
|
|
||||||
static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, bool egress,
|
static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, bool egress,
|
||||||
bool is_4_19) {
|
const unsigned kver) {
|
||||||
uint32_t sock_uid = bpf_get_socket_uid(skb);
|
uint32_t sock_uid = bpf_get_socket_uid(skb);
|
||||||
uint64_t cookie = bpf_get_socket_cookie(skb);
|
uint64_t cookie = bpf_get_socket_cookie(skb);
|
||||||
UidTagValue* utag = bpf_cookie_tag_map_lookup_elem(&cookie);
|
UidTagValue* utag = bpf_cookie_tag_map_lookup_elem(&cookie);
|
||||||
@@ -314,7 +333,7 @@ static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, boo
|
|||||||
return PASS;
|
return PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int match = bpf_owner_match(skb, sock_uid, egress, is_4_19);
|
int match = bpf_owner_match(skb, sock_uid, egress, kver);
|
||||||
if (egress && (match == DROP)) {
|
if (egress && (match == DROP)) {
|
||||||
// If an outbound packet is going to be dropped, we do not count that
|
// If an outbound packet is going to be dropped, we do not count that
|
||||||
// traffic.
|
// traffic.
|
||||||
@@ -362,25 +381,25 @@ static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, boo
|
|||||||
DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/ingress/stats$4_19", AID_ROOT, AID_SYSTEM,
|
DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/ingress/stats$4_19", AID_ROOT, AID_SYSTEM,
|
||||||
bpf_cgroup_ingress_4_19, KVER(4, 19, 0), KVER_INF)
|
bpf_cgroup_ingress_4_19, KVER(4, 19, 0), KVER_INF)
|
||||||
(struct __sk_buff* skb) {
|
(struct __sk_buff* skb) {
|
||||||
return bpf_traffic_account(skb, INGRESS, /* is_4_19 */ true);
|
return bpf_traffic_account(skb, INGRESS, KVER(4, 19, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/ingress/stats$4_14", AID_ROOT, AID_SYSTEM,
|
DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/ingress/stats$4_14", AID_ROOT, AID_SYSTEM,
|
||||||
bpf_cgroup_ingress_4_14, KVER_NONE, KVER(4, 19, 0))
|
bpf_cgroup_ingress_4_14, KVER_NONE, KVER(4, 19, 0))
|
||||||
(struct __sk_buff* skb) {
|
(struct __sk_buff* skb) {
|
||||||
return bpf_traffic_account(skb, INGRESS, /* is_4_19 */ false);
|
return bpf_traffic_account(skb, INGRESS, KVER_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/egress/stats$4_19", AID_ROOT, AID_SYSTEM,
|
DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/egress/stats$4_19", AID_ROOT, AID_SYSTEM,
|
||||||
bpf_cgroup_egress_4_19, KVER(4, 19, 0), KVER_INF)
|
bpf_cgroup_egress_4_19, KVER(4, 19, 0), KVER_INF)
|
||||||
(struct __sk_buff* skb) {
|
(struct __sk_buff* skb) {
|
||||||
return bpf_traffic_account(skb, EGRESS, /* is_4_19 */ true);
|
return bpf_traffic_account(skb, EGRESS, KVER(4, 19, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/egress/stats$4_14", AID_ROOT, AID_SYSTEM,
|
DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/egress/stats$4_14", AID_ROOT, AID_SYSTEM,
|
||||||
bpf_cgroup_egress_4_14, KVER_NONE, KVER(4, 19, 0))
|
bpf_cgroup_egress_4_14, KVER_NONE, KVER(4, 19, 0))
|
||||||
(struct __sk_buff* skb) {
|
(struct __sk_buff* skb) {
|
||||||
return bpf_traffic_account(skb, EGRESS, /* is_4_19 */ false);
|
return bpf_traffic_account(skb, EGRESS, KVER_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// WARNING: Android T's non-updatable netd depends on the name of this program.
|
// WARNING: Android T's non-updatable netd depends on the name of this program.
|
||||||
|
|||||||
Reference in New Issue
Block a user