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