blob: 64c675a18c571200adb34e3ab6c4898415f1b152 [file] [log] [blame]
Chenbo Feng75b410b2018-10-10 15:01:19 -07001/*
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#ifndef LOG_TAG
18#define LOG_TAG "bpfloader"
19#endif
20
21#include <arpa/inet.h>
Joel Fernandesd76a2002018-10-16 13:19:58 -070022#include <dirent.h>
Chenbo Feng75b410b2018-10-10 15:01:19 -070023#include <elf.h>
24#include <error.h>
25#include <fcntl.h>
26#include <inttypes.h>
27#include <linux/bpf.h>
28#include <linux/unistd.h>
29#include <net/if.h>
30#include <stdint.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <unistd.h>
35
36#include <sys/mman.h>
37#include <sys/socket.h>
38#include <sys/stat.h>
39#include <sys/types.h>
40
Steven Morelanda48639e2022-02-07 23:15:48 +000041#include <android-base/logging.h>
Steven Moreland0f10f3f2019-12-12 14:22:34 -080042#include <android-base/macros.h>
Joel Fernandesd3ec8712019-01-11 06:22:05 -050043#include <android-base/properties.h>
Chenbo Feng75b410b2018-10-10 15:01:19 -070044#include <android-base/stringprintf.h>
Joel Fernandesd76a2002018-10-16 13:19:58 -070045#include <android-base/strings.h>
Chenbo Feng75b410b2018-10-10 15:01:19 -070046#include <android-base/unique_fd.h>
Joel Fernandesd76a2002018-10-16 13:19:58 -070047#include <libbpf_android.h>
Chenbo Feng75b410b2018-10-10 15:01:19 -070048#include <log/log.h>
Maciej Żenczykowski4e4dea02022-12-10 17:58:59 +000049#include "BpfSyscallWrappers.h"
Chenbo Feng75b410b2018-10-10 15:01:19 -070050#include "bpf/BpfUtils.h"
Chenbo Feng75b410b2018-10-10 15:01:19 -070051
Joel Fernandesd76a2002018-10-16 13:19:58 -070052using android::base::EndsWith;
Maciej Żenczykowski41817132022-06-03 08:41:04 -070053using android::bpf::domain;
Joel Fernandesd76a2002018-10-16 13:19:58 -070054using std::string;
Chenbo Feng75b410b2018-10-10 15:01:19 -070055
Maciej Żenczykowski057ef342022-07-18 03:04:37 -070056bool exists(const char* const path) {
57 int v = access(path, F_OK);
58 if (!v) {
59 ALOGI("%s exists.", path);
60 return true;
61 }
62 if (errno == ENOENT) return false;
63 ALOGE("FATAL: access(%s, F_OK) -> %d [%d:%s]", path, v, errno, strerror(errno));
64 abort(); // can only hit this if permissions (likely selinux) are screwed up
65}
66
Maciej Żenczykowskiae58e7e2022-07-01 10:01:44 -070067// Networking-related program types are limited to the Tethering Apex
68// to prevent things from breaking due to conflicts on mainline updates
69// (exception made for socket filters, ie. xt_bpf for potential use in iptables,
70// or for attaching to sockets directly)
71constexpr bpf_prog_type kPlatformAllowedProgTypes[] = {
72 BPF_PROG_TYPE_KPROBE,
73 BPF_PROG_TYPE_PERF_EVENT,
74 BPF_PROG_TYPE_SOCKET_FILTER,
75 BPF_PROG_TYPE_TRACEPOINT,
Paul Lawrence7fb8b542022-07-19 16:13:49 -070076 BPF_PROG_TYPE_UNSPEC, // Will be replaced with fuse bpf program type
Maciej Żenczykowskiae58e7e2022-07-01 10:01:44 -070077};
78
Yu-Ting Tseng9c56a5a2024-01-11 20:43:05 -080079constexpr bpf_prog_type kUprobestatsAllowedProgTypes[] = {
80 BPF_PROG_TYPE_KPROBE,
81};
82
Steven Moreland0f10f3f2019-12-12 14:22:34 -080083// see b/162057235. For arbitrary program types, the concern is that due to the lack of
84// SELinux access controls over BPF program attachpoints, we have no way to control the
85// attachment of programs to shared resources (or to detect when a shared resource
86// has one BPF program replace another that is attached there)
87constexpr bpf_prog_type kVendorAllowedProgTypes[] = {
Stephane Lee16c93602022-03-08 17:27:09 -080088 BPF_PROG_TYPE_SOCKET_FILTER,
Steven Moreland0f10f3f2019-12-12 14:22:34 -080089};
90
Connor O'Brien6c0ce9f2022-12-01 20:08:17 -080091const android::bpf::Location locations[] = {
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -080092 // Core operating system
93 {
94 .dir = "/system/etc/bpf/",
95 .prefix = "",
Maciej Żenczykowski41817132022-06-03 08:41:04 -070096 .allowedDomainBitmask = domainToBitmask(domain::platform),
Maciej Żenczykowskiae58e7e2022-07-01 10:01:44 -070097 .allowedProgTypes = kPlatformAllowedProgTypes,
98 .allowedProgTypesLength = arraysize(kPlatformAllowedProgTypes),
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -080099 },
Yu-Ting Tseng9c56a5a2024-01-11 20:43:05 -0800100 // uprobestats
101 {
102 .dir = "/system/etc/bpf/uprobestats/",
103 .prefix = "uprobestats/",
104 .allowedDomainBitmask = domainToBitmask(domain::platform),
105 .allowedProgTypes = kUprobestatsAllowedProgTypes,
106 .allowedProgTypesLength = arraysize(kUprobestatsAllowedProgTypes),
107 },
Steven Moreland0f10f3f2019-12-12 14:22:34 -0800108 // Vendor operating system
109 {
110 .dir = "/vendor/etc/bpf/",
111 .prefix = "vendor/",
Maciej Żenczykowski41817132022-06-03 08:41:04 -0700112 .allowedDomainBitmask = domainToBitmask(domain::vendor),
Steven Moreland0f10f3f2019-12-12 14:22:34 -0800113 .allowedProgTypes = kVendorAllowedProgTypes,
114 .allowedProgTypesLength = arraysize(kVendorAllowedProgTypes),
115 },
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800116};
Chenbo Feng75b410b2018-10-10 15:01:19 -0700117
Connor O'Brien6c0ce9f2022-12-01 20:08:17 -0800118int loadAllElfObjects(const android::bpf::Location& location) {
Maciej Żenczykowski89515d92020-06-14 19:27:33 -0700119 int retVal = 0;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700120 DIR* dir;
121 struct dirent* ent;
122
Steven Moreland0f10f3f2019-12-12 14:22:34 -0800123 if ((dir = opendir(location.dir)) != NULL) {
Joel Fernandesd76a2002018-10-16 13:19:58 -0700124 while ((ent = readdir(dir)) != NULL) {
125 string s = ent->d_name;
126 if (!EndsWith(s, ".o")) continue;
127
Steven Moreland0f10f3f2019-12-12 14:22:34 -0800128 string progPath(location.dir);
Hungming Chen4b8e9822020-09-10 15:51:59 +0800129 progPath += s;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700130
Maciej Żenczykowski89515d92020-06-14 19:27:33 -0700131 bool critical;
Connor O'Brien6c0ce9f2022-12-01 20:08:17 -0800132 int ret = android::bpf::loadProg(progPath.c_str(), &critical, location);
Maciej Żenczykowski89515d92020-06-14 19:27:33 -0700133 if (ret) {
134 if (critical) retVal = ret;
135 ALOGE("Failed to load object: %s, ret: %s", progPath.c_str(), std::strerror(-ret));
136 } else {
137 ALOGI("Loaded object: %s", progPath.c_str());
138 }
Joel Fernandesd76a2002018-10-16 13:19:58 -0700139 }
140 closedir(dir);
141 }
Maciej Żenczykowski89515d92020-06-14 19:27:33 -0700142 return retVal;
Joel Fernandesd76a2002018-10-16 13:19:58 -0700143}
144
Maciej Żenczykowskiebfacde2022-12-05 13:33:43 +0000145int createSysFsBpfSubDir(const char* const prefix) {
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800146 if (*prefix) {
147 mode_t prevUmask = umask(0);
148
149 string s = "/sys/fs/bpf/";
150 s += prefix;
151
152 errno = 0;
153 int ret = mkdir(s.c_str(), S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
154 if (ret && errno != EEXIST) {
Maciej Żenczykowskiebfacde2022-12-05 13:33:43 +0000155 const int err = errno;
156 ALOGE("Failed to create directory: %s, ret: %s", s.c_str(), std::strerror(err));
157 return -err;
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800158 }
159
160 umask(prevUmask);
161 }
Maciej Żenczykowskiebfacde2022-12-05 13:33:43 +0000162 return 0;
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800163}
164
Maciej Żenczykowski03b6caa2022-12-03 09:38:05 +0000165// Technically 'value' doesn't need to be newline terminated, but it's best
166// to include a newline to match 'echo "value" > /proc/sys/...foo' behaviour,
167// which is usually how kernel devs test the actual sysctl interfaces.
168int writeProcSysFile(const char *filename, const char *value) {
169 android::base::unique_fd fd(open(filename, O_WRONLY | O_CLOEXEC));
170 if (fd < 0) {
171 const int err = errno;
172 ALOGE("open('%s', O_WRONLY | O_CLOEXEC) -> %s", filename, strerror(err));
173 return -err;
174 }
175 int len = strlen(value);
176 int v = write(fd, value, len);
177 if (v < 0) {
178 const int err = errno;
179 ALOGE("write('%s', '%s', %d) -> %s", filename, value, len, strerror(err));
180 return -err;
181 }
182 if (v != len) {
183 // In practice, due to us only using this for /proc/sys/... files, this can't happen.
184 ALOGE("write('%s', '%s', %d) -> short write [%d]", filename, value, len, v);
185 return -EINVAL;
186 }
187 return 0;
188}
189
Steven Morelanda48639e2022-02-07 23:15:48 +0000190int main(int argc, char** argv) {
191 (void)argc;
192 android::base::InitLogging(argv, &android::base::KernelLogger);
193
Maciej Żenczykowski03b6caa2022-12-03 09:38:05 +0000194 // Enable the eBPF JIT -- but do note that on 64-bit kernels it is likely
Maciej Żenczykowski8aa34a72022-12-13 12:37:03 +0000195 // already force enabled by the kernel config option BPF_JIT_ALWAYS_ON.
Maciej Żenczykowski052cda12022-12-12 00:15:53 +0000196 // (Note: this (open) will fail with ENOENT 'No such file or directory' if
197 // kernel does not have CONFIG_BPF_JIT=y)
Maciej Żenczykowski8aa34a72022-12-13 12:37:03 +0000198 // BPF_JIT is required by R VINTF (which means 4.14/4.19/5.4 kernels),
199 // but 4.14/4.19 were released with P & Q, and only 5.4 is new in R+.
Michael Bestas30b81fc2024-03-11 01:48:26 +0200200 if (writeProcSysFile("/proc/sys/net/core/bpf_jit_enable", "1\n") &&
201 android::bpf::isAtLeastKernelVersion(4, 14, 0)) return 1;
Maciej Żenczykowski03b6caa2022-12-03 09:38:05 +0000202
203 // Enable JIT kallsyms export for privileged users only
Maciej Żenczykowski052cda12022-12-12 00:15:53 +0000204 // (Note: this (open) will fail with ENOENT 'No such file or directory' if
205 // kernel does not have CONFIG_HAVE_EBPF_JIT=y)
Michael Bestas30b81fc2024-03-11 01:48:26 +0200206 if (writeProcSysFile("/proc/sys/net/core/bpf_jit_kallsyms", "1\n") &&
207 android::bpf::isAtLeastKernelVersion(4, 14, 0)) return 1;
Maciej Żenczykowski03b6caa2022-12-03 09:38:05 +0000208
Maciej Żenczykowski41817132022-06-03 08:41:04 -0700209 // Create all the pin subdirectories
210 // (this must be done first to allow selinux_context and pin_subdir functionality,
211 // which could otherwise fail with ENOENT during object pinning or renaming,
212 // due to ordering issues)
Steven Moreland0f10f3f2019-12-12 14:22:34 -0800213 for (const auto& location : locations) {
Maciej Żenczykowskiebfacde2022-12-05 13:33:43 +0000214 if (createSysFsBpfSubDir(location.prefix)) return 1;
Maciej Żenczykowski41817132022-06-03 08:41:04 -0700215 }
216
217 // Load all ELF objects, create programs and maps, and pin them
218 for (const auto& location : locations) {
Steven Moreland0f10f3f2019-12-12 14:22:34 -0800219 if (loadAllElfObjects(location) != 0) {
Maciej Żenczykowskid8a45782021-01-14 23:36:32 -0800220 ALOGE("=== CRITICAL FAILURE LOADING BPF PROGRAMS FROM %s ===", location.dir);
Hungming Chen4b8e9822020-09-10 15:51:59 +0800221 ALOGE("If this triggers reliably, you're probably missing kernel options or patches.");
222 ALOGE("If this triggers randomly, you might be hitting some memory allocation "
223 "problems or startup script race.");
224 ALOGE("--- DO NOT EXPECT SYSTEM TO BOOT SUCCESSFULLY ---");
225 sleep(20);
226 return 2;
227 }
Maciej Żenczykowski89515d92020-06-14 19:27:33 -0700228 }
Joel Fernandesd3ec8712019-01-11 06:22:05 -0500229
Maciej Żenczykowskiab8fd4c2023-10-10 16:20:43 -0700230 if (android::base::SetProperty("bpf.progs_loaded", "1") == false) {
231 ALOGE("Failed to set bpf.progs_loaded property");
232 return 1;
233 }
234
Joel Fernandesd3ec8712019-01-11 06:22:05 -0500235 return 0;
Chenbo Feng75b410b2018-10-10 15:01:19 -0700236}