• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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  * bpf_existence_test.cpp - checks that the device has expected BPF programs and maps
17  */
18 
19 #include <cstdint>
20 #include <set>
21 #include <string>
22 
23 #include <android/api-level.h>
24 #include <android-base/properties.h>
25 #include <android-modules-utils/sdk_level.h>
26 #include <bpf/BpfUtils.h>
27 
28 #include <gtest/gtest.h>
29 
30 using std::find;
31 using std::set;
32 using std::string;
33 
34 using android::modules::sdklevel::IsAtLeastR;
35 using android::modules::sdklevel::IsAtLeastS;
36 using android::modules::sdklevel::IsAtLeastT;
37 
38 // Mainline development branches lack the constant for the current development OS.
39 #ifndef __ANDROID_API_T__
40 #define __ANDROID_API_T__ 33
41 #endif
42 
43 #define PLATFORM "/sys/fs/bpf/"
44 #define TETHERING "/sys/fs/bpf/tethering/"
45 #define PRIVATE "/sys/fs/bpf/net_private/"
46 #define SHARED "/sys/fs/bpf/net_shared/"
47 #define NETD "/sys/fs/bpf/netd_shared/"
48 
49 class BpfExistenceTest : public ::testing::Test {
50 };
51 
52 static const set<string> INTRODUCED_R = {
53     PLATFORM "map_offload_tether_ingress_map",
54     PLATFORM "map_offload_tether_limit_map",
55     PLATFORM "map_offload_tether_stats_map",
56     PLATFORM "prog_offload_schedcls_ingress_tether_ether",
57     PLATFORM "prog_offload_schedcls_ingress_tether_rawip",
58 };
59 
60 static const set<string> INTRODUCED_S = {
61     TETHERING "map_offload_tether_dev_map",
62     TETHERING "map_offload_tether_downstream4_map",
63     TETHERING "map_offload_tether_downstream64_map",
64     TETHERING "map_offload_tether_downstream6_map",
65     TETHERING "map_offload_tether_error_map",
66     TETHERING "map_offload_tether_limit_map",
67     TETHERING "map_offload_tether_stats_map",
68     TETHERING "map_offload_tether_upstream4_map",
69     TETHERING "map_offload_tether_upstream6_map",
70     TETHERING "map_test_tether_downstream6_map",
71     TETHERING "prog_offload_schedcls_tether_downstream4_ether",
72     TETHERING "prog_offload_schedcls_tether_downstream4_rawip",
73     TETHERING "prog_offload_schedcls_tether_downstream6_ether",
74     TETHERING "prog_offload_schedcls_tether_downstream6_rawip",
75     TETHERING "prog_offload_schedcls_tether_upstream4_ether",
76     TETHERING "prog_offload_schedcls_tether_upstream4_rawip",
77     TETHERING "prog_offload_schedcls_tether_upstream6_ether",
78     TETHERING "prog_offload_schedcls_tether_upstream6_rawip",
79 };
80 
81 static const set<string> REMOVED_S = {
82     PLATFORM "map_offload_tether_ingress_map",
83     PLATFORM "map_offload_tether_limit_map",
84     PLATFORM "map_offload_tether_stats_map",
85     PLATFORM "prog_offload_schedcls_ingress_tether_ether",
86     PLATFORM "prog_offload_schedcls_ingress_tether_rawip",
87 };
88 
89 static const set<string> INTRODUCED_T = {
90     SHARED "map_block_blocked_ports_map",
91     SHARED "map_clatd_clat_egress4_map",
92     SHARED "map_clatd_clat_ingress6_map",
93     SHARED "map_dscp_policy_ipv4_dscp_policies_map",
94     SHARED "map_dscp_policy_ipv4_socket_to_policies_map_A",
95     SHARED "map_dscp_policy_ipv4_socket_to_policies_map_B",
96     SHARED "map_dscp_policy_ipv6_dscp_policies_map",
97     SHARED "map_dscp_policy_ipv6_socket_to_policies_map_A",
98     SHARED "map_dscp_policy_ipv6_socket_to_policies_map_B",
99     SHARED "map_dscp_policy_switch_comp_map",
100     NETD "map_netd_app_uid_stats_map",
101     NETD "map_netd_configuration_map",
102     NETD "map_netd_cookie_tag_map",
103     NETD "map_netd_iface_index_name_map",
104     NETD "map_netd_iface_stats_map",
105     NETD "map_netd_stats_map_A",
106     NETD "map_netd_stats_map_B",
107     NETD "map_netd_uid_counterset_map",
108     NETD "map_netd_uid_owner_map",
109     NETD "map_netd_uid_permission_map",
110     SHARED "prog_clatd_schedcls_egress4_clat_ether",
111     SHARED "prog_clatd_schedcls_egress4_clat_rawip",
112     SHARED "prog_clatd_schedcls_ingress6_clat_ether",
113     SHARED "prog_clatd_schedcls_ingress6_clat_rawip",
114     NETD "prog_netd_cgroupskb_egress_stats",
115     NETD "prog_netd_cgroupskb_ingress_stats",
116     NETD "prog_netd_cgroupsock_inet_create",
117     NETD "prog_netd_schedact_ingress_account",
118     NETD "prog_netd_skfilter_allowlist_xtbpf",
119     NETD "prog_netd_skfilter_denylist_xtbpf",
120     NETD "prog_netd_skfilter_egress_xtbpf",
121     NETD "prog_netd_skfilter_ingress_xtbpf",
122 };
123 
124 static const set<string> INTRODUCED_T_5_4 = {
125     SHARED "prog_block_bind4_block_port",
126     SHARED "prog_block_bind6_block_port",
127 };
128 
129 static const set<string> INTRODUCED_T_5_15 = {
130     SHARED "prog_dscp_policy_schedcls_set_dscp_ether",
131     SHARED "prog_dscp_policy_schedcls_set_dscp_raw_ip",
132 };
133 
134 static const set<string> REMOVED_T = {
135 };
136 
addAll(set<string> * a,const set<string> & b)137 void addAll(set<string>* a, const set<string>& b) {
138     a->insert(b.begin(), b.end());
139 }
140 
removeAll(set<string> * a,const set<string> & b)141 void removeAll(set<string>* a, const set<string>& b) {
142     for (const auto& toRemove : b) {
143         a->erase(toRemove);
144     }
145 }
146 
getFileLists(set<string> * expected,set<string> * unexpected)147 void getFileLists(set<string>* expected, set<string>* unexpected) {
148     unexpected->clear();
149     expected->clear();
150 
151     addAll(unexpected, INTRODUCED_R);
152     addAll(unexpected, INTRODUCED_S);
153     addAll(unexpected, INTRODUCED_T);
154 
155     if (IsAtLeastR()) {
156         addAll(expected, INTRODUCED_R);
157         removeAll(unexpected, INTRODUCED_R);
158         // Nothing removed in R.
159     }
160 
161     if (IsAtLeastS()) {
162         addAll(expected, INTRODUCED_S);
163         removeAll(expected, REMOVED_S);
164 
165         addAll(unexpected, REMOVED_S);
166         removeAll(unexpected, INTRODUCED_S);
167     }
168 
169     // Nothing added or removed in SCv2.
170 
171     if (IsAtLeastT()) {
172         addAll(expected, INTRODUCED_T);
173         if (android::bpf::isAtLeastKernelVersion(5, 4, 0)) addAll(expected, INTRODUCED_T_5_4);
174         if (android::bpf::isAtLeastKernelVersion(5, 15, 0)) addAll(expected, INTRODUCED_T_5_15);
175         removeAll(expected, REMOVED_T);
176 
177         addAll(unexpected, REMOVED_T);
178         removeAll(unexpected, INTRODUCED_T);
179     }
180 }
181 
checkFiles()182 void checkFiles() {
183     set<string> mustExist;
184     set<string> mustNotExist;
185 
186     getFileLists(&mustExist, &mustNotExist);
187 
188     for (const auto& file : mustExist) {
189         EXPECT_EQ(0, access(file.c_str(), R_OK)) << file << " does not exist";
190     }
191     for (const auto& file : mustNotExist) {
192         int ret = access(file.c_str(), R_OK);
193         int err = errno;
194         EXPECT_EQ(-1, ret) << file << " unexpectedly exists";
195         if (ret == -1) {
196             EXPECT_EQ(ENOENT, err) << " accessing " << file << " failed with errno " << err;
197         }
198     }
199 }
200 
TEST_F(BpfExistenceTest,TestPrograms)201 TEST_F(BpfExistenceTest, TestPrograms) {
202     SKIP_IF_BPF_NOT_SUPPORTED;
203 
204     // Pre-flight check to ensure test has been updated.
205     uint64_t buildVersionSdk = android_get_device_api_level();
206     ASSERT_NE(0, buildVersionSdk) << "Unable to determine device SDK version";
207     if (buildVersionSdk > __ANDROID_API_T__ && buildVersionSdk != __ANDROID_API_FUTURE__) {
208             FAIL() << "Unknown OS version " << buildVersionSdk << ", please update this test";
209     }
210 
211     // Only unconfined root is guaranteed to be able to access everything in /sys/fs/bpf.
212     ASSERT_EQ(0, getuid()) << "This test must run as root.";
213 
214     checkFiles();
215 }
216