• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <cutils/android_filesystem_config.h>
20 #include <linux/if.h>
21 #include <linux/if_ether.h>
22 #include <linux/in.h>
23 #include <linux/in6.h>
24 
25 #ifdef __cplusplus
26 #include <string_view>
27 #include "XtBpfProgLocations.h"
28 #endif
29 
30 // This header file is shared by eBPF kernel programs (C) and netd (C++) and
31 // some of the maps are also accessed directly from Java mainline module code.
32 //
33 // Hence: explicitly pad all relevant structures and assert that their size
34 // is the sum of the sizes of their fields.
35 #define STRUCT_SIZE(name, size) _Static_assert(sizeof(name) == (size), "Incorrect struct size.")
36 
37 typedef struct {
38     uint32_t uid;
39     uint32_t tag;
40 } UidTagValue;
41 STRUCT_SIZE(UidTagValue, 2 * 4);  // 8
42 
43 typedef struct {
44     uint32_t uid;
45     uint32_t tag;
46     uint32_t counterSet;
47     uint32_t ifaceIndex;
48 } StatsKey;
49 STRUCT_SIZE(StatsKey, 4 * 4);  // 16
50 
51 typedef struct {
52     uint64_t rxPackets;
53     uint64_t rxBytes;
54     uint64_t txPackets;
55     uint64_t txBytes;
56 } StatsValue;
57 STRUCT_SIZE(StatsValue, 4 * 8);  // 32
58 
59 #ifdef __cplusplus
60 static inline StatsValue& operator+=(StatsValue& lhs, const StatsValue& rhs) {
61     lhs.rxPackets += rhs.rxPackets;
62     lhs.rxBytes += rhs.rxBytes;
63     lhs.txPackets += rhs.txPackets;
64     lhs.txBytes += rhs.txBytes;
65     return lhs;
66 }
67 #endif
68 
69 typedef struct {
70     char name[IFNAMSIZ];
71 } IfaceValue;
72 STRUCT_SIZE(IfaceValue, 16);
73 
74 typedef struct {
75   uint64_t timestampNs;
76   uint32_t ifindex;
77   uint32_t length;
78 
79   uint32_t uid;
80   uint32_t tag;
81 
82   __be16 sport;
83   __be16 dport;
84 
85   bool egress:1,
86        wakeup:1;
87   uint8_t ipProto;
88   uint8_t tcpFlags;
89   uint8_t ipVersion; // 4=IPv4, 6=IPv6, 0=unknown
90 } PacketTrace;
91 STRUCT_SIZE(PacketTrace, 8+4+4 + 4+4 + 2+2 + 1+1+1+1);
92 
93 // Since we cannot garbage collect the stats map since device boot, we need to make these maps as
94 // large as possible. The maximum size of number of map entries we can have is depend on the rlimit
95 // of MEM_LOCK granted to netd. The memory space needed by each map can be calculated by the
96 // following fomula:
97 //      elem_size = 40 + roundup(key_size, 8) + roundup(value_size, 8)
98 //      cost = roundup_pow_of_two(max_entries) * 16 + elem_size * max_entries +
99 //              elem_size * number_of_CPU
100 // And the cost of each map currently used is(assume the device have 8 CPUs):
101 // cookie_tag_map:      key:  8 bytes, value:  8 bytes, cost:  822592 bytes    =   823Kbytes
102 // uid_counter_set_map: key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes
103 // app_uid_stats_map:   key:  4 bytes, value: 32 bytes, cost: 1062784 bytes    =  1063Kbytes
104 // uid_stats_map:       key: 16 bytes, value: 32 bytes, cost: 1142848 bytes    =  1143Kbytes
105 // tag_stats_map:       key: 16 bytes, value: 32 bytes, cost: 1142848 bytes    =  1143Kbytes
106 // iface_index_name_map:key:  4 bytes, value: 16 bytes, cost:   80896 bytes    =    81Kbytes
107 // iface_stats_map:     key:  4 bytes, value: 32 bytes, cost:   97024 bytes    =    97Kbytes
108 // dozable_uid_map:     key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes
109 // standby_uid_map:     key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes
110 // powersave_uid_map:   key:  4 bytes, value:  1 bytes, cost:  145216 bytes    =   145Kbytes
111 // packet_trace_ringbuf:key:  0 bytes, value: 24 bytes, cost:   32768 bytes    =    32Kbytes
112 // total:                                                                         4962Kbytes
113 // It takes maximum 4.9MB kernel memory space if all maps are full, which requires any devices
114 // running this module to have a memlock rlimit to be larger then 5MB. In the old qtaguid module,
115 // we don't have a total limit for data entries but only have limitation of tags each uid can have.
116 // (default is 1024 in kernel);
117 
118 // 'static' - otherwise these constants end up in .rodata in the resulting .o post compilation
119 static const int COOKIE_UID_MAP_SIZE = 10000;
120 static const int UID_COUNTERSET_MAP_SIZE = 4000;
121 static const int APP_STATS_MAP_SIZE = 10000;
122 static const int STATS_MAP_SIZE = 5000;
123 static const int IFACE_INDEX_NAME_MAP_SIZE = 1000;
124 static const int IFACE_STATS_MAP_SIZE = 1000;
125 static const int CONFIGURATION_MAP_SIZE = 2;
126 static const int UID_OWNER_MAP_SIZE = 4000;
127 static const int INGRESS_DISCARD_MAP_SIZE = 100;
128 static const int PACKET_TRACE_BUF_SIZE = 32 * 1024;
129 static const int DATA_SAVER_ENABLED_MAP_SIZE = 1;
130 
131 #ifdef __cplusplus
132 
133 #define BPF_NETD_PATH "/sys/fs/bpf/netd_shared/"
134 
135 #define BPF_EGRESS_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupskb_egress_stats"
136 #define BPF_INGRESS_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupskb_ingress_stats"
137 
138 #define ASSERT_STRING_EQUAL(s1, s2) \
139     static_assert(std::string_view(s1) == std::string_view(s2), "mismatch vs Android T netd")
140 
141 /* -=-=-=-=- WARNING -=-=-=-=-
142  *
143  * These 4 xt_bpf program paths are actually defined by:
144  *   //system/netd/include/mainline/XtBpfProgLocations.h
145  * which is intentionally a non-automerged location.
146  *
147  * They are *UNCHANGEABLE* due to being hard coded in Android T's netd binary
148  * as such we have compile time asserts that things match.
149  * (which will be validated during build on mainline-prod branch against old system/netd)
150  *
151  * If you break this, netd on T will fail to start with your tethering mainline module.
152  */
153 ASSERT_STRING_EQUAL(XT_BPF_INGRESS_PROG_PATH,   BPF_NETD_PATH "prog_netd_skfilter_ingress_xtbpf");
154 ASSERT_STRING_EQUAL(XT_BPF_EGRESS_PROG_PATH,    BPF_NETD_PATH "prog_netd_skfilter_egress_xtbpf");
155 ASSERT_STRING_EQUAL(XT_BPF_ALLOWLIST_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilter_allowlist_xtbpf");
156 ASSERT_STRING_EQUAL(XT_BPF_DENYLIST_PROG_PATH,  BPF_NETD_PATH "prog_netd_skfilter_denylist_xtbpf");
157 
158 #define CGROUP_INET_CREATE_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupsock_inet_create"
159 #define CGROUP_INET_RELEASE_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupsockrelease_inet_release"
160 #define CGROUP_BIND4_PROG_PATH BPF_NETD_PATH "prog_netd_bind4_inet4_bind"
161 #define CGROUP_BIND6_PROG_PATH BPF_NETD_PATH "prog_netd_bind6_inet6_bind"
162 #define CGROUP_CONNECT4_PROG_PATH BPF_NETD_PATH "prog_netd_connect4_inet4_connect"
163 #define CGROUP_CONNECT6_PROG_PATH BPF_NETD_PATH "prog_netd_connect6_inet6_connect"
164 #define CGROUP_UDP4_RECVMSG_PROG_PATH BPF_NETD_PATH "prog_netd_recvmsg4_udp4_recvmsg"
165 #define CGROUP_UDP6_RECVMSG_PROG_PATH BPF_NETD_PATH "prog_netd_recvmsg6_udp6_recvmsg"
166 #define CGROUP_UDP4_SENDMSG_PROG_PATH BPF_NETD_PATH "prog_netd_sendmsg4_udp4_sendmsg"
167 #define CGROUP_UDP6_SENDMSG_PROG_PATH BPF_NETD_PATH "prog_netd_sendmsg6_udp6_sendmsg"
168 #define CGROUP_GETSOCKOPT_PROG_PATH BPF_NETD_PATH "prog_netd_getsockopt_prog"
169 #define CGROUP_SETSOCKOPT_PROG_PATH BPF_NETD_PATH "prog_netd_setsockopt_prog"
170 
171 #define TC_BPF_INGRESS_ACCOUNT_PROG_NAME "prog_netd_schedact_ingress_account"
172 #define TC_BPF_INGRESS_ACCOUNT_PROG_PATH BPF_NETD_PATH TC_BPF_INGRESS_ACCOUNT_PROG_NAME
173 
174 #define COOKIE_TAG_MAP_PATH BPF_NETD_PATH "map_netd_cookie_tag_map"
175 #define UID_COUNTERSET_MAP_PATH BPF_NETD_PATH "map_netd_uid_counterset_map"
176 #define APP_UID_STATS_MAP_PATH BPF_NETD_PATH "map_netd_app_uid_stats_map"
177 #define STATS_MAP_A_PATH BPF_NETD_PATH "map_netd_stats_map_A"
178 #define STATS_MAP_B_PATH BPF_NETD_PATH "map_netd_stats_map_B"
179 #define IFACE_INDEX_NAME_MAP_PATH BPF_NETD_PATH "map_netd_iface_index_name_map"
180 #define IFACE_STATS_MAP_PATH BPF_NETD_PATH "map_netd_iface_stats_map"
181 #define CONFIGURATION_MAP_PATH BPF_NETD_PATH "map_netd_configuration_map"
182 #define UID_OWNER_MAP_PATH BPF_NETD_PATH "map_netd_uid_owner_map"
183 #define UID_PERMISSION_MAP_PATH BPF_NETD_PATH "map_netd_uid_permission_map"
184 #define INGRESS_DISCARD_MAP_PATH BPF_NETD_PATH "map_netd_ingress_discard_map"
185 #define PACKET_TRACE_RINGBUF_PATH BPF_NETD_PATH "map_netd_packet_trace_ringbuf"
186 #define PACKET_TRACE_ENABLED_MAP_PATH BPF_NETD_PATH "map_netd_packet_trace_enabled_map"
187 #define DATA_SAVER_ENABLED_MAP_PATH BPF_NETD_PATH "map_netd_data_saver_enabled_map"
188 #define LOCAL_NET_ACCESS_MAP_PATH BPF_NETD_PATH "map_netd_local_net_access_map"
189 #define LOCAL_NET_BLOCKED_UID_MAP_PATH BPF_NETD_PATH "map_netd_local_net_blocked_uid_map"
190 
191 #endif // __cplusplus
192 
193 // LINT.IfChange(match_type)
194 enum UidOwnerMatchType : uint32_t {
195     NO_MATCH = 0,
196     HAPPY_BOX_MATCH = (1 << 0),
197     PENALTY_BOX_USER_MATCH = (1 << 1),
198     DOZABLE_MATCH = (1 << 2),
199     STANDBY_MATCH = (1 << 3),
200     POWERSAVE_MATCH = (1 << 4),
201     RESTRICTED_MATCH = (1 << 5),
202     LOW_POWER_STANDBY_MATCH = (1 << 6),
203     IIF_MATCH = (1 << 7),
204     LOCKDOWN_VPN_MATCH = (1 << 8),
205     OEM_DENY_1_MATCH = (1 << 9),
206     OEM_DENY_2_MATCH = (1 << 10),
207     OEM_DENY_3_MATCH = (1 << 11),
208     BACKGROUND_MATCH = (1 << 12),
209     PENALTY_BOX_ADMIN_MATCH = (1 << 13),
210 };
211 // LINT.ThenChange(../framework/src/android/net/BpfNetMapsConstants.java)
212 
213 enum BpfPermissionMatch : uint8_t {
214     BPF_PERMISSION_INTERNET = 1 << 2,
215     BPF_PERMISSION_UPDATE_DEVICE_STATS = 1 << 3,
216 };
217 // In production we use two identical stats maps to record per uid stats and
218 // do swap and clean based on the configuration specified here. The statsMapType
219 // value in configuration map specified which map is currently in use.
220 enum StatsMapType : uint32_t {
221     SELECT_MAP_A,
222     SELECT_MAP_B,
223 };
224 
225 // TODO: change the configuration object from a bitmask to an object with clearer
226 // semantics, like a struct.
227 typedef uint32_t BpfConfig;
228 static const BpfConfig DEFAULT_CONFIG = 0;
229 
230 typedef struct {
231     // Allowed interface index. Only applicable if IIF_MATCH is set in the rule bitmask above.
232     uint32_t iif;
233     // A bitmask of enum values in UidOwnerMatchType.
234     uint32_t rule;
235 } UidOwnerValue;
236 STRUCT_SIZE(UidOwnerValue, 2 * 4);  // 8
237 
238 typedef struct {
239     // The destination ip of the incoming packet.  IPv4 uses IPv4-mapped IPv6 address format.
240     struct in6_addr daddr;
241 } IngressDiscardKey;
242 STRUCT_SIZE(IngressDiscardKey, 16);  // 16
243 
244 typedef struct {
245     // Allowed interface indexes.  Use same value multiple times if you just want to match 1 value.
246     uint32_t iif[2];
247 } IngressDiscardValue;
248 STRUCT_SIZE(IngressDiscardValue, 2 * 4);  // 8
249 
250 typedef struct {
251   // Longest prefix match length in bits (value from 0 to 192).
252   uint32_t lpm_bitlen;
253   uint32_t if_index;
254   // IPv4 uses IPv4-mapped IPv6 address format.
255   struct in6_addr remote_ip6;
256   // u16 instead of u8 to avoid padding due to alignment requirement.
257   uint16_t protocol;
258   __be16 remote_port;
259 } LocalNetAccessKey;
260 STRUCT_SIZE(LocalNetAccessKey, 4 + 4 + 16 + 2 + 2);  // 28
261 
262 // Entry in the configuration map that stores which UID rules are enabled.
263 #define UID_RULES_CONFIGURATION_KEY 0
264 // Entry in the configuration map that stores which stats map is currently in use.
265 #define CURRENT_STATS_MAP_CONFIGURATION_KEY 1
266 // Entry in the data saver enabled map that stores whether data saver is enabled or not.
267 #define DATA_SAVER_ENABLED_KEY 0
268 
269 #undef STRUCT_SIZE
270 
271 // DROP_IF_SET is set of rules that DROP if rule is globally enabled, and per-uid bit is set
272 #define DROP_IF_SET (STANDBY_MATCH | OEM_DENY_1_MATCH | OEM_DENY_2_MATCH | OEM_DENY_3_MATCH)
273 // DROP_IF_UNSET is set of rules that should DROP if globally enabled, and per-uid bit is NOT set
274 #define DROP_IF_UNSET (DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH \
275                         | LOW_POWER_STANDBY_MATCH | BACKGROUND_MATCH)
276 
277 // Warning: funky bit-wise arithmetic: in parallel, for all DROP_IF_SET/UNSET rules
278 // check whether the rules are globally enabled, and if so whether the rules are
279 // set/unset for the specific uid.  DROP if that is the case for ANY of the rules.
280 // We achieve this by masking out only the bits/rules we're interested in checking,
281 // and negating (via bit-wise xor) the bits/rules that should drop if unset.
isBlockedByUidRules(BpfConfig enabledRules,uint32_t uidRules)282 static inline bool isBlockedByUidRules(BpfConfig enabledRules, uint32_t uidRules) {
283     return enabledRules & (DROP_IF_SET | DROP_IF_UNSET) & (uidRules ^ DROP_IF_UNSET);
284 }
285 
is_system_uid(uint32_t uid)286 static inline bool is_system_uid(uint32_t uid) {
287     // MIN_SYSTEM_UID is AID_ROOT == 0, so uint32_t is *always* >= 0
288     // MAX_SYSTEM_UID is AID_NOBODY == 9999, while AID_APP_START == 10000
289     return ((uid % AID_USER_OFFSET) < AID_APP_START);
290 }
291