-----BEGIN PGP SIGNATURE----- iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCaS5huQAKCRDorT+BmrEO eIsnAJ9kJ9OjiHpwigt9XwjTrGcbD1hQ0QCfSw2VHyS9TLyzt7DZsQ3AYU+WVVA= =/SH/ -----END PGP SIGNATURE----- gpgsig -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgPpdpjxPACTIhnlvYz0GM4BR7FJ +rYv3jMbfxNKD3JvcAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQHUBff/oLA1TO7KbbZDsBJZmFVcXgFmG+2K3aaKq9F0tiaT1kiNeHdjXpaLI07p344 TExz9CBvFVft81pJyRBwY= -----END SSH SIGNATURE----- Merge tag 'android-16.0.0_r4' into staging/lineage-23.2_merge-android-16.0.0_r4 Android 16.0.0 release 4 # -----BEGIN PGP SIGNATURE----- # # iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCaS5huQAKCRDorT+BmrEO # eIsnAJ9kJ9OjiHpwigt9XwjTrGcbD1hQ0QCfSw2VHyS9TLyzt7DZsQ3AYU+WVVA= # =/SH/ # -----END PGP SIGNATURE----- # gpg: Signature made Tue Dec 2 05:49:13 2025 EET # gpg: using DSA key 4340D13570EF945E83810964E8AD3F819AB10E78 # gpg: Good signature from "The Android Open Source Project <initial-contribution@android.com>" [ultimate] # By Yan Yan (203) and others # Via Automerger Merge Worker (1173) and others * tag 'android-16.0.0_r4': (1057 commits) Use string for CREATE_APP_SPECIFIC_NETWORK permission bpf: move MSS calculation under CE check to avoid overhead BpfNetworkStats: use `atomic` for ifindex cache when possible NetBpfLoad: remove pointless 0 write. bpf: remove obsolete isAtLeastR/Sv2/25Q3 NetBpfLoad: use global `api_level_full` directly in NetBpfLoad Log validated underlying network count that's available for VCN underlying network selection BpfUtils: fix sdk level detection logic for 25Q3+ Add RTMGRP_IPV6_IFINFO bpf: remove BPFLOADER_MAINLINE_U_QPR3_VERSION bpf: move BPFLOADER_MAINLINE_S_VERSION into bpf_map_def.h Reduce log level for BluetoothSocket errors Bump the min sdk of Tethering BpfNetworkStats: apparently RiscV isn't actually a 64-bit architecture. KernelUtils.h: isAtLeastKernelVersion(x,y,z) - default 'z' to 0 bpf_existence_test - update for tcp acc ecn bpf: tcpAccECN: eliminate header file and move more fully into netd BpfMap: shorten error strings to enable SSO (on 64-bit) BpfNetworkStats: enforce that IfaceValue access is lock-free NetBpfLoad: use libbpf based on mainline beta flag, part 2 ... Conflicts: bpf/headers/include/bpf/KernelUtils.h bpf/progs/netd.h Change-Id: I76a7aadc1405c6621e17f3d1b6b87640d84f5794
278 lines
11 KiB
C++
278 lines
11 KiB
C++
/*
|
|
* Copyright (C) 2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <cutils/android_filesystem_config.h>
|
|
#include <linux/if.h>
|
|
#include <linux/if_ether.h>
|
|
#include <linux/in.h>
|
|
#include <linux/in6.h>
|
|
|
|
#ifdef __cplusplus
|
|
#include <string_view>
|
|
#include "XtBpfProgLocations.h"
|
|
#endif
|
|
|
|
// This header file is shared by eBPF kernel programs (C) and netd (C++) and
|
|
// some of the maps are also accessed directly from Java mainline module code.
|
|
//
|
|
// Hence: explicitly pad all relevant structures and assert that their size
|
|
// is the sum of the sizes of their fields.
|
|
#define STRUCT_SIZE(name, size) _Static_assert(sizeof(name) == (size), "Incorrect struct size.")
|
|
|
|
typedef struct {
|
|
uint32_t uid;
|
|
uint32_t tag;
|
|
} UidTagValue;
|
|
STRUCT_SIZE(UidTagValue, 2 * 4); // 8
|
|
|
|
typedef struct {
|
|
uint32_t uid;
|
|
uint32_t tag;
|
|
uint32_t counterSet;
|
|
uint32_t ifaceIndex;
|
|
} StatsKey;
|
|
STRUCT_SIZE(StatsKey, 4 * 4); // 16
|
|
|
|
typedef struct {
|
|
uint64_t rxPackets;
|
|
uint64_t rxBytes;
|
|
uint64_t txPackets;
|
|
uint64_t txBytes;
|
|
} StatsValue;
|
|
STRUCT_SIZE(StatsValue, 4 * 8); // 32
|
|
|
|
#ifdef __cplusplus
|
|
static inline StatsValue& operator+=(StatsValue& lhs, const StatsValue& rhs) {
|
|
lhs.rxPackets += rhs.rxPackets;
|
|
lhs.rxBytes += rhs.rxBytes;
|
|
lhs.txPackets += rhs.txPackets;
|
|
lhs.txBytes += rhs.txBytes;
|
|
return lhs;
|
|
}
|
|
#endif
|
|
|
|
typedef struct {
|
|
char name[IFNAMSIZ];
|
|
} IfaceValue;
|
|
STRUCT_SIZE(IfaceValue, 16);
|
|
|
|
typedef struct {
|
|
uint64_t timestampNs;
|
|
uint32_t ifindex;
|
|
uint32_t length;
|
|
|
|
uint32_t uid;
|
|
uint32_t tag;
|
|
|
|
__be16 sport;
|
|
__be16 dport;
|
|
|
|
bool egress:1,
|
|
wakeup:1;
|
|
uint8_t ipProto;
|
|
uint8_t tcpFlags;
|
|
uint8_t ipVersion; // 4=IPv4, 6=IPv6, 0=unknown
|
|
} PacketTrace;
|
|
STRUCT_SIZE(PacketTrace, 8+4+4 + 4+4 + 2+2 + 1+1+1+1);
|
|
|
|
typedef struct {
|
|
uint64_t cookie;
|
|
} SkStorageValue;
|
|
STRUCT_SIZE(SkStorageValue, 8);
|
|
|
|
#define STATS_MAP_SIZE 5000
|
|
#define CONFIGURATION_MAP_SIZE 2
|
|
|
|
#ifdef __cplusplus
|
|
|
|
#define BPF_NETD_PATH "/sys/fs/bpf/netd_shared/"
|
|
|
|
#define BPF_EGRESS_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupskb_egress_stats"
|
|
#define BPF_INGRESS_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupskb_ingress_stats"
|
|
|
|
#define ASSERT_STRING_EQUAL(s1, s2) \
|
|
static_assert(std::string_view(s1) == std::string_view(s2), "mismatch vs Android T netd")
|
|
|
|
/* -=-=-=-=- WARNING -=-=-=-=-
|
|
*
|
|
* These 4 xt_bpf program paths are actually defined by:
|
|
* //system/netd/include/mainline/XtBpfProgLocations.h
|
|
* which is intentionally a non-automerged location.
|
|
*
|
|
* They are *UNCHANGEABLE* due to being hard coded in Android T's netd binary
|
|
* as such we have compile time asserts that things match.
|
|
* (which will be validated during build on mainline-prod branch against old system/netd)
|
|
*
|
|
* If you break this, netd on T will fail to start with your tethering mainline module.
|
|
*/
|
|
ASSERT_STRING_EQUAL(XT_BPF_INGRESS_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilter_ingress_xtbpf");
|
|
ASSERT_STRING_EQUAL(XT_BPF_EGRESS_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilter_egress_xtbpf");
|
|
ASSERT_STRING_EQUAL(XT_BPF_ALLOWLIST_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilter_allowlist_xtbpf");
|
|
ASSERT_STRING_EQUAL(XT_BPF_DENYLIST_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilter_denylist_xtbpf");
|
|
|
|
#define CGROUP_INET_CREATE_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupsock_inet_create"
|
|
#define CGROUP_INET_RELEASE_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupsockrelease_inet_release"
|
|
#define CGROUP_BIND4_PROG_PATH BPF_NETD_PATH "prog_netd_bind4_inet4_bind"
|
|
#define CGROUP_BIND6_PROG_PATH BPF_NETD_PATH "prog_netd_bind6_inet6_bind"
|
|
#define CGROUP_CONNECT4_PROG_PATH BPF_NETD_PATH "prog_netd_connect4_inet4_connect"
|
|
#define CGROUP_CONNECT6_PROG_PATH BPF_NETD_PATH "prog_netd_connect6_inet6_connect"
|
|
#define CGROUP_UDP4_RECVMSG_PROG_PATH BPF_NETD_PATH "prog_netd_recvmsg4_udp4_recvmsg"
|
|
#define CGROUP_UDP6_RECVMSG_PROG_PATH BPF_NETD_PATH "prog_netd_recvmsg6_udp6_recvmsg"
|
|
#define CGROUP_UDP4_SENDMSG_PROG_PATH BPF_NETD_PATH "prog_netd_sendmsg4_udp4_sendmsg"
|
|
#define CGROUP_UDP6_SENDMSG_PROG_PATH BPF_NETD_PATH "prog_netd_sendmsg6_udp6_sendmsg"
|
|
#define CGROUP_GETSOCKOPT_PROG_PATH BPF_NETD_PATH "prog_netd_getsockopt_prog"
|
|
#define CGROUP_SETSOCKOPT_PROG_PATH BPF_NETD_PATH "prog_netd_setsockopt_prog"
|
|
|
|
#define TC_BPF_INGRESS_ACCOUNT_PROG_NAME "prog_netd_schedact_ingress_account"
|
|
#define TC_BPF_INGRESS_ACCOUNT_PROG_PATH BPF_NETD_PATH TC_BPF_INGRESS_ACCOUNT_PROG_NAME
|
|
|
|
#define COOKIE_TAG_MAP_PATH BPF_NETD_PATH "map_netd_cookie_tag_map"
|
|
#define UID_COUNTERSET_MAP_PATH BPF_NETD_PATH "map_netd_uid_counterset_map"
|
|
#define APP_UID_STATS_MAP_PATH BPF_NETD_PATH "map_netd_app_uid_stats_map"
|
|
#define STATS_MAP_A_PATH BPF_NETD_PATH "map_netd_stats_map_A"
|
|
#define STATS_MAP_B_PATH BPF_NETD_PATH "map_netd_stats_map_B"
|
|
#define IFACE_INDEX_NAME_MAP_PATH BPF_NETD_PATH "map_netd_iface_index_name_map"
|
|
#define IFACE_STATS_MAP_PATH BPF_NETD_PATH "map_netd_iface_stats_map"
|
|
#define CONFIGURATION_MAP_PATH BPF_NETD_PATH "map_netd_configuration_map"
|
|
#define UID_OWNER_MAP_PATH BPF_NETD_PATH "map_netd_uid_owner_map"
|
|
#define UID_PERMISSION_MAP_PATH BPF_NETD_PATH "map_netd_uid_permission_map"
|
|
#define INGRESS_DISCARD_MAP_PATH BPF_NETD_PATH "map_netd_ingress_discard_map"
|
|
#define PACKET_TRACE_RINGBUF_PATH BPF_NETD_PATH "map_netd_packet_trace_ringbuf"
|
|
#define PACKET_TRACE_ENABLED_MAP_PATH BPF_NETD_PATH "map_netd_packet_trace_enabled_map"
|
|
#define DATA_SAVER_ENABLED_MAP_PATH BPF_NETD_PATH "map_netd_data_saver_enabled_map"
|
|
#define LOCAL_NET_ACCESS_MAP_PATH BPF_NETD_PATH "map_netd_local_net_access_map"
|
|
#define LOCAL_NET_BLOCKED_UID_MAP_PATH BPF_NETD_PATH "map_netd_local_net_blocked_uid_map"
|
|
|
|
#define L4S_INGRESS_ETHER_PROG_PATH BPF_NETD_PATH "prog_netd_schedcls_ingress_accecn_eth"
|
|
#define L4S_EGRESS_ETHER_PROG_PATH BPF_NETD_PATH "prog_netd_schedcls_egress_accecn_eth"
|
|
#define L4S_INGRESS_RAWIP_PROG_PATH BPF_NETD_PATH "prog_netd_schedcls_ingress_accecn_rawip"
|
|
#define L4S_EGRESS_RAWIP_PROG_PATH BPF_NETD_PATH "prog_netd_schedcls_egress_accecn_rawip"
|
|
#define L4S_OPTIONS_SOCKOPS_PROG_PATH BPF_NETD_PATH "prog_netd_sockops_accecn_option"
|
|
|
|
#define L4S_ACCECN_CE_MAP_PATH BPF_NETD_PATH "map_netd_l4s_accecn_ce_map"
|
|
#define L4S_ACCECN_BYTE_MAP_PATH BPF_NETD_PATH "map_netd_l4s_accecn_byte_map"
|
|
#define L4S_ACCECN_MSS_MAP_PATH BPF_NETD_PATH "map_netd_l4s_accecn_mss_map"
|
|
|
|
#endif // __cplusplus
|
|
|
|
typedef struct {
|
|
uint64_t ceb;
|
|
uint64_t e0b;
|
|
uint64_t e1b;
|
|
} EcnByteCounters;
|
|
STRUCT_SIZE(EcnByteCounters, 3 * 8); // 24
|
|
|
|
// LINT.IfChange(match_type)
|
|
enum UidOwnerMatchType : uint32_t {
|
|
NO_MATCH = 0,
|
|
HAPPY_BOX_MATCH = (1 << 0),
|
|
PENALTY_BOX_USER_MATCH = (1 << 1),
|
|
DOZABLE_MATCH = (1 << 2),
|
|
STANDBY_MATCH = (1 << 3),
|
|
POWERSAVE_MATCH = (1 << 4),
|
|
RESTRICTED_MATCH = (1 << 5),
|
|
LOW_POWER_STANDBY_MATCH = (1 << 6),
|
|
IIF_MATCH = (1 << 7),
|
|
LOCKDOWN_VPN_MATCH = (1 << 8),
|
|
OEM_DENY_1_MATCH = (1 << 9),
|
|
OEM_DENY_2_MATCH = (1 << 10),
|
|
OEM_DENY_3_MATCH = (1 << 11),
|
|
BACKGROUND_MATCH = (1 << 12),
|
|
PENALTY_BOX_ADMIN_MATCH = (1 << 13),
|
|
};
|
|
// LINT.ThenChange(../framework/src/android/net/BpfNetMapsConstants.java)
|
|
|
|
enum BpfPermissionMatch : uint8_t {
|
|
BPF_PERMISSION_INTERNET = 1 << 2,
|
|
BPF_PERMISSION_UPDATE_DEVICE_STATS = 1 << 3,
|
|
};
|
|
// In production we use two identical stats maps to record per uid stats and
|
|
// do swap and clean based on the configuration specified here. The statsMapType
|
|
// value in configuration map specified which map is currently in use.
|
|
enum StatsMapType : uint32_t {
|
|
SELECT_MAP_A,
|
|
SELECT_MAP_B,
|
|
};
|
|
|
|
// TODO: change the configuration object from a bitmask to an object with clearer
|
|
// semantics, like a struct.
|
|
typedef uint32_t BpfConfig;
|
|
static const BpfConfig DEFAULT_CONFIG = 0;
|
|
|
|
typedef struct {
|
|
// Allowed interface index. Only applicable if IIF_MATCH is set in the rule bitmask above.
|
|
uint32_t iif;
|
|
// A bitmask of enum values in UidOwnerMatchType.
|
|
uint32_t rule;
|
|
} UidOwnerValue;
|
|
STRUCT_SIZE(UidOwnerValue, 2 * 4); // 8
|
|
|
|
typedef struct {
|
|
// The destination ip of the incoming packet. IPv4 uses IPv4-mapped IPv6 address format.
|
|
struct in6_addr daddr;
|
|
} IngressDiscardKey;
|
|
STRUCT_SIZE(IngressDiscardKey, 16); // 16
|
|
|
|
typedef struct {
|
|
// Allowed interface indexes. Use same value multiple times if you just want to match 1 value.
|
|
uint32_t iif[2];
|
|
} IngressDiscardValue;
|
|
STRUCT_SIZE(IngressDiscardValue, 2 * 4); // 8
|
|
|
|
typedef struct {
|
|
// Longest prefix match length in bits (value from 0 to 192).
|
|
uint32_t lpm_bitlen;
|
|
uint32_t if_index;
|
|
// IPv4 uses IPv4-mapped IPv6 address format.
|
|
struct in6_addr remote_ip6;
|
|
// u16 instead of u8 to avoid padding due to alignment requirement.
|
|
uint16_t protocol;
|
|
__be16 remote_port;
|
|
} LocalNetAccessKey;
|
|
STRUCT_SIZE(LocalNetAccessKey, 4 + 4 + 16 + 2 + 2); // 28
|
|
|
|
// Entry in the configuration map that stores which UID rules are enabled.
|
|
#define UID_RULES_CONFIGURATION_KEY 0
|
|
// Entry in the configuration map that stores which stats map is currently in use.
|
|
#define CURRENT_STATS_MAP_CONFIGURATION_KEY 1
|
|
// Entry in the data saver enabled map that stores whether data saver is enabled or not.
|
|
#define DATA_SAVER_ENABLED_KEY 0
|
|
|
|
// DROP_IF_SET is set of rules that DROP if rule is globally enabled, and per-uid bit is set
|
|
#define DROP_IF_SET (STANDBY_MATCH | OEM_DENY_1_MATCH | OEM_DENY_2_MATCH | OEM_DENY_3_MATCH)
|
|
// DROP_IF_UNSET is set of rules that should DROP if globally enabled, and per-uid bit is NOT set
|
|
#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.
|
|
// We achieve this by masking out only the bits/rules we're interested in checking,
|
|
// and negating (via bit-wise xor) the bits/rules that should drop if unset.
|
|
static inline bool isBlockedByUidRules(BpfConfig enabledRules, uint32_t uidRules) {
|
|
return enabledRules & (DROP_IF_SET | DROP_IF_UNSET) & (uidRules ^ DROP_IF_UNSET);
|
|
}
|
|
|
|
static inline bool is_system_uid(uint32_t uid) {
|
|
// MIN_SYSTEM_UID is AID_ROOT == 0, so uint32_t is *always* >= 0
|
|
// MAX_SYSTEM_UID is AID_NOBODY == 9999, while AID_APP_START == 10000
|
|
return ((uid % AID_USER_OFFSET) < AID_APP_START);
|
|
}
|