1 /*
2 * Copyright (C) 2017 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 #define LOG_TAG "BpfUtils"
18
19 #include "bpf/BpfUtils.h"
20
21 #include <elf.h>
22 #include <inttypes.h>
23 #include <linux/bpf.h>
24 #include <linux/if_ether.h>
25 #include <linux/in.h>
26 #include <linux/pfkeyv2.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/mman.h>
30 #include <sys/resource.h>
31 #include <sys/socket.h>
32 #include <sys/stat.h>
33 #include <sys/utsname.h>
34 #include <sstream>
35 #include <string>
36
37 #include <android-base/properties.h>
38 #include <android-base/unique_fd.h>
39 #include <log/log.h>
40 #include <processgroup/processgroup.h>
41
42 using android::base::unique_fd;
43
44 // The buffer size for the buffer that records program loading logs, needs to be large enough for
45 // the largest kernel program.
46
47 namespace android {
48 namespace bpf {
49
getSocketCookie(int sockFd)50 uint64_t getSocketCookie(int sockFd) {
51 uint64_t sock_cookie;
52 socklen_t cookie_len = sizeof(sock_cookie);
53 int res = getsockopt(sockFd, SOL_SOCKET, SO_COOKIE, &sock_cookie, &cookie_len);
54 if (res < 0) {
55 res = -errno;
56 ALOGE("Failed to get socket cookie: %s\n", strerror(errno));
57 errno = -res;
58 // 0 is an invalid cookie. See sock_gen_cookie.
59 return NONEXISTENT_COOKIE;
60 }
61 return sock_cookie;
62 }
63
synchronizeKernelRCU()64 int synchronizeKernelRCU() {
65 // This is a temporary hack for network stats map swap on devices running
66 // 4.9 kernels. The kernel code of socket release on pf_key socket will
67 // explicitly call synchronize_rcu() which is exactly what we need.
68 int pfSocket = socket(AF_KEY, SOCK_RAW | SOCK_CLOEXEC, PF_KEY_V2);
69
70 if (pfSocket < 0) {
71 int ret = -errno;
72 ALOGE("create PF_KEY socket failed: %s", strerror(errno));
73 return ret;
74 }
75
76 // When closing socket, synchronize_rcu() gets called in sock_release().
77 if (close(pfSocket)) {
78 int ret = -errno;
79 ALOGE("failed to close the PF_KEY socket: %s", strerror(errno));
80 return ret;
81 }
82 return 0;
83 }
84
setrlimitForTest()85 int setrlimitForTest() {
86 // Set the memory rlimit for the test process if the default MEMLOCK rlimit is not enough.
87 struct rlimit limit = {
88 .rlim_cur = 1073741824, // 1 GiB
89 .rlim_max = 1073741824, // 1 GiB
90 };
91 int res = setrlimit(RLIMIT_MEMLOCK, &limit);
92 if (res) {
93 ALOGE("Failed to set the default MEMLOCK rlimit: %s", strerror(errno));
94 }
95 return res;
96 }
97
98 #define KVER(a, b, c) ((a)*65536 + (b)*256 + (c))
99
kernelVersion()100 unsigned kernelVersion() {
101 struct utsname buf;
102 int ret = uname(&buf);
103 if (ret) return 0;
104
105 unsigned kver_major;
106 unsigned kver_minor;
107 unsigned kver_sub;
108 char dummy;
109 ret = sscanf(buf.release, "%u.%u.%u%c", &kver_major, &kver_minor, &kver_sub, &dummy);
110 // Check the device kernel version
111 if (ret < 3) return 0;
112
113 return KVER(kver_major, kver_minor, kver_sub);
114 }
115
BpfLevelToString(BpfLevel bpfLevel)116 std::string BpfLevelToString(BpfLevel bpfLevel) {
117 switch (bpfLevel) {
118 case BpfLevel::NONE:
119 return "None [pre-4.9 or pre-P]";
120 case BpfLevel::BASIC_4_9:
121 return "Basic [4.9 P+]";
122 case BpfLevel::EXTENDED_4_14:
123 return "Extended [4.14]";
124 case BpfLevel::EXTENDED_4_19:
125 return "Extended [4.19]";
126 case BpfLevel::EXTENDED_5_4:
127 return "Extended [5.4+]";
128 // No default statement. We want to see errors of the form:
129 // "enumeration value 'BPF_LEVEL_xxx' not handled in switch [-Werror,-Wswitch]".
130 }
131 }
132
getUncachedBpfSupportLevel()133 static BpfLevel getUncachedBpfSupportLevel() {
134 unsigned kver = kernelVersion();
135
136 if (kver >= KVER(5, 4, 0)) return BpfLevel::EXTENDED_5_4;
137 if (kver >= KVER(4, 19, 0)) return BpfLevel::EXTENDED_4_19;
138 if (kver >= KVER(4, 14, 0)) return BpfLevel::EXTENDED_4_14;
139
140 // Override for devices launched with O but now on a 4.9-P+ kernel.
141 bool ebpf_supported = base::GetBoolProperty("ro.kernel.ebpf.supported", false);
142 if (ebpf_supported) return BpfLevel::BASIC_4_9;
143
144 uint64_t api_level = base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
145 if (api_level == 0) {
146 ALOGE("Cannot determine initial API level of the device");
147 api_level = base::GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
148 }
149
150 // Check if the device is shipped originally with android P.
151 if (api_level < MINIMUM_API_REQUIRED) return BpfLevel::NONE;
152
153 if (kver >= KVER(4, 9, 0)) return BpfLevel::BASIC_4_9;
154
155 return BpfLevel::NONE;
156 }
157
getBpfSupportLevel()158 BpfLevel getBpfSupportLevel() {
159 static BpfLevel cache = getUncachedBpfSupportLevel();
160 return cache;
161 }
162
163 } // namespace bpf
164 } // namespace android
165