Snap for 12199973 from 31446f67c5c1909113201466f6cfbbc771b1be4f to 24Q4-release
Change-Id: Ibadb6d9f29f5fba3519856bf68cc719b2f935468
diff --git a/loader/BpfLoader.cpp b/loader/BpfLoader.cpp
index 3f13291..f180f4e 100644
--- a/loader/BpfLoader.cpp
+++ b/loader/BpfLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,154 +14,11 @@
* limitations under the License.
*/
-#define LOG_TAG "BpfLoader"
-
-#include <arpa/inet.h>
-#include <dirent.h>
-#include <elf.h>
-#include <error.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <linux/bpf.h>
-#include <linux/unistd.h>
-#include <net/if.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/mman.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
#include <libbpf_android.h>
-#include <log/log.h>
-#include "BpfSyscallWrappers.h"
-#include "bpf/BpfUtils.h"
-using android::base::EndsWith;
-using std::string;
-
-// Networking-related program types are limited to the Tethering Apex
-// to prevent things from breaking due to conflicts on mainline updates
-// (exception made for socket filters, ie. xt_bpf for potential use in iptables,
-// or for attaching to sockets directly)
-constexpr bpf_prog_type kPlatformAllowedProgTypes[] = {
- BPF_PROG_TYPE_KPROBE,
- BPF_PROG_TYPE_PERF_EVENT,
- BPF_PROG_TYPE_SOCKET_FILTER,
- BPF_PROG_TYPE_TRACEPOINT,
- BPF_PROG_TYPE_UNSPEC, // Will be replaced with fuse bpf program type
-};
-
-constexpr bpf_prog_type kUprobestatsAllowedProgTypes[] = {
- BPF_PROG_TYPE_KPROBE,
-};
-
-// see b/162057235. For arbitrary program types, the concern is that due to the lack of
-// SELinux access controls over BPF program attachpoints, we have no way to control the
-// attachment of programs to shared resources (or to detect when a shared resource
-// has one BPF program replace another that is attached there)
-constexpr bpf_prog_type kVendorAllowedProgTypes[] = {
- BPF_PROG_TYPE_SOCKET_FILTER,
-};
-
-const android::bpf::Location locations[] = {
- // Core operating system
- {
- .dir = "/system/etc/bpf/",
- .prefix = "",
- .allowedProgTypes = kPlatformAllowedProgTypes,
- .allowedProgTypesLength = arraysize(kPlatformAllowedProgTypes),
- },
- // uprobestats
- {
- .dir = "/system/etc/bpf/uprobestats/",
- .prefix = "uprobestats/",
- .allowedProgTypes = kUprobestatsAllowedProgTypes,
- .allowedProgTypesLength = arraysize(kUprobestatsAllowedProgTypes),
- },
- // Vendor operating system
- {
- .dir = "/vendor/etc/bpf/",
- .prefix = "vendor/",
- .allowedProgTypes = kVendorAllowedProgTypes,
- .allowedProgTypesLength = arraysize(kVendorAllowedProgTypes),
- },
-};
-
-int loadAllElfObjects(const android::bpf::Location& location) {
- int retVal = 0;
- DIR* dir;
- struct dirent* ent;
-
- if ((dir = opendir(location.dir)) != NULL) {
- while ((ent = readdir(dir)) != NULL) {
- string s = ent->d_name;
- if (!EndsWith(s, ".o")) continue;
-
- string progPath(location.dir);
- progPath += s;
-
- bool critical;
- int ret = android::bpf::loadProg(progPath.c_str(), &critical, location);
- if (ret) {
- if (critical) retVal = ret;
- ALOGE("Failed to load object: %s, ret: %s", progPath.c_str(), std::strerror(-ret));
- } else {
- ALOGV("Loaded object: %s", progPath.c_str());
- }
- }
- closedir(dir);
- }
- return retVal;
-}
-
-int createSysFsBpfSubDir(const char* const prefix) {
- if (*prefix) {
- mode_t prevUmask = umask(0);
-
- string s = "/sys/fs/bpf/";
- s += prefix;
-
- errno = 0;
- int ret = mkdir(s.c_str(), S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
- if (ret && errno != EEXIST) {
- const int err = errno;
- ALOGE("Failed to create directory: %s, ret: %s", s.c_str(), std::strerror(err));
- return -err;
- }
-
- umask(prevUmask);
- }
- return 0;
-}
-
-int main(int __unused argc, char** argv, char * const envp[]) {
- android::base::InitLogging(argv, &android::base::KernelLogger);
-
- // Load all ELF objects, create programs and maps, and pin them
- for (const auto& location : locations) {
- if (createSysFsBpfSubDir(location.prefix) || loadAllElfObjects(location)) {
- ALOGE("=== CRITICAL FAILURE LOADING BPF PROGRAMS FROM %s ===", location.dir);
- ALOGE("If this triggers reliably, you're probably missing kernel options or patches.");
- ALOGE("If this triggers randomly, you might be hitting some memory allocation "
- "problems or startup script race.");
- ALOGE("--- DO NOT EXPECT SYSTEM TO BOOT SUCCESSFULLY ---");
- sleep(20);
- return 120;
- }
- }
-
- const char * args[] = { "/apex/com.android.tethering/bin/netbpfload", "done", NULL, };
- execve(args[0], (char**)args, envp);
- ALOGE("FATAL: execve(): %d[%s]", errno, strerror(errno));
- return 121;
+__noreturn int main() {
+ initLogging();
+ legacyBpfLoader();
+ execNetBpfLoadDone();
+ // unreachable
}
diff --git a/loader/Loader.cpp b/loader/Loader.cpp
index 6ec7458..cdeca4e 100644
--- a/loader/Loader.cpp
+++ b/loader/Loader.cpp
@@ -46,6 +46,7 @@
#include <android-base/cmsg.h>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
@@ -57,11 +58,13 @@
// Unspecified attach type is 0 which is BPF_CGROUP_INET_INGRESS.
#define BPF_ATTACH_TYPE_UNSPEC BPF_CGROUP_INET_INGRESS
+using android::base::EndsWith;
using android::base::StartsWith;
using android::base::unique_fd;
using std::ifstream;
using std::ios;
using std::optional;
+using std::strerror;
using std::string;
using std::vector;
@@ -877,5 +880,153 @@
return ret;
}
+// Networking-related program types are limited to the Tethering Apex
+// to prevent things from breaking due to conflicts on mainline updates
+// (exception made for socket filters, ie. xt_bpf for potential use in iptables,
+// or for attaching to sockets directly)
+constexpr bpf_prog_type kPlatformAllowedProgTypes[] = {
+ BPF_PROG_TYPE_KPROBE,
+ BPF_PROG_TYPE_PERF_EVENT,
+ BPF_PROG_TYPE_SOCKET_FILTER,
+ BPF_PROG_TYPE_TRACEPOINT,
+ BPF_PROG_TYPE_UNSPEC, // Will be replaced with fuse bpf program type
+};
+
+constexpr bpf_prog_type kUprobestatsAllowedProgTypes[] = {
+ BPF_PROG_TYPE_KPROBE,
+};
+
+// see b/162057235. For arbitrary program types, the concern is that due to the lack of
+// SELinux access controls over BPF program attachpoints, we have no way to control the
+// attachment of programs to shared resources (or to detect when a shared resource
+// has one BPF program replace another that is attached there)
+constexpr bpf_prog_type kVendorAllowedProgTypes[] = {
+ BPF_PROG_TYPE_SOCKET_FILTER,
+};
+
+const Location locations[] = {
+ // Core operating system
+ {
+ .dir = "/system/etc/bpf/",
+ .prefix = "",
+ .allowedProgTypes = kPlatformAllowedProgTypes,
+ .allowedProgTypesLength = arraysize(kPlatformAllowedProgTypes),
+ },
+ // uprobestats
+ {
+ .dir = "/system/etc/bpf/uprobestats/",
+ .prefix = "uprobestats/",
+ .allowedProgTypes = kUprobestatsAllowedProgTypes,
+ .allowedProgTypesLength = arraysize(kUprobestatsAllowedProgTypes),
+ },
+ // Vendor operating system
+ {
+ .dir = "/vendor/etc/bpf/",
+ .prefix = "vendor/",
+ .allowedProgTypes = kVendorAllowedProgTypes,
+ .allowedProgTypesLength = arraysize(kVendorAllowedProgTypes),
+ },
+};
+
+int loadAllElfObjects(const Location& location) {
+ int retVal = 0;
+ DIR* dir;
+ struct dirent* ent;
+
+ if ((dir = opendir(location.dir)) != NULL) {
+ while ((ent = readdir(dir)) != NULL) {
+ string s = ent->d_name;
+ if (!EndsWith(s, ".o")) continue;
+
+ string progPath(location.dir);
+ progPath += s;
+
+ bool critical;
+ int ret = loadProg(progPath.c_str(), &critical, location);
+ if (ret) {
+ if (critical) retVal = ret;
+ ALOGE("Failed to load object: %s, ret: %s", progPath.c_str(), strerror(-ret));
+ } else {
+ ALOGV("Loaded object: %s", progPath.c_str());
+ }
+ }
+ closedir(dir);
+ }
+ return retVal;
+}
+
+int createSysFsBpfSubDir(const char* const prefix) {
+ if (*prefix) {
+ mode_t prevUmask = umask(0);
+
+ string s = "/sys/fs/bpf/";
+ s += prefix;
+
+ errno = 0;
+ int ret = mkdir(s.c_str(), S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
+ if (ret && errno != EEXIST) {
+ const int err = errno;
+ ALOGE("Failed to create directory: %s, ret: %s", s.c_str(), strerror(err));
+ return -err;
+ }
+
+ umask(prevUmask);
+ }
+ return 0;
+}
+
} // namespace bpf
} // namespace android
+
+// ----- extern C stuff for rust below here -----
+
+void initLogging() {
+ // since we only ever get called from mainline NetBpfLoad
+ // (see packages/modules/Connectivity/netbpfload/NetBpfLoad.cpp around line 516)
+ // and there no arguments, so we can just pretend/assume this is the case.
+ const char* argv[] = {"/system/bin/bpfloader", NULL};
+ android::base::InitLogging(const_cast<char**>(argv), &android::base::KernelLogger);
+}
+
+void legacyBpfLoader() {
+ // Load all ELF objects, create programs and maps, and pin them
+ for (const auto& location : android::bpf::locations) {
+ if (android::bpf::createSysFsBpfSubDir(location.prefix) ||
+ android::bpf::loadAllElfObjects(location)) {
+ ALOGE("=== CRITICAL FAILURE LOADING BPF PROGRAMS FROM %s ===", location.dir);
+ ALOGE("If this triggers reliably, you're probably missing kernel options or patches.");
+ ALOGE("If this triggers randomly, you might be hitting some memory allocation "
+ "problems or startup script race.");
+ ALOGE("--- DO NOT EXPECT SYSTEM TO BOOT SUCCESSFULLY ---");
+ sleep(20);
+ exit(120);
+ }
+ }
+}
+
+void execNetBpfLoadDone() {
+ const char* args[] = {"/apex/com.android.tethering/bin/netbpfload", "done", NULL};
+ execve(args[0], (char**)args, environ);
+ ALOGE("FATAL: execve(): %d[%s]", errno, strerror(errno));
+ exit(121);
+}
+
+void logVerbose(const char* msg) {
+ ALOGV("%s", msg);
+}
+
+void logDebug(const char* msg) {
+ ALOGD("%s", msg);
+}
+
+void logInfo(const char* msg) {
+ ALOGI("%s", msg);
+}
+
+void logWarn(const char* msg) {
+ ALOGW("%s", msg);
+}
+
+void logError(const char* msg) {
+ ALOGE("%s", msg);
+}
diff --git a/loader/include/libbpf_android.h b/loader/include/libbpf_android.h
index 0a98a1d..fbdae6f 100644
--- a/loader/include/libbpf_android.h
+++ b/loader/include/libbpf_android.h
@@ -17,6 +17,8 @@
#pragma once
+#ifdef __cplusplus
+
#include <linux/bpf.h>
#include <fstream>
@@ -39,3 +41,24 @@
} // namespace bpf
} // namespace android
+
+extern "C" {
+#else // __cplusplus
+#define __noreturn
+#endif // __cplusplus
+
+// The C++ portion of the BpfLoader is exposed as 3 functions to be called in order.
+void initLogging();
+void legacyBpfLoader();
+__noreturn void execNetBpfLoadDone();
+
+// For logging from rust
+void logVerbose(const char* msg);
+void logDebug(const char* msg);
+void logInfo(const char* msg);
+void logWarn(const char* msg);
+void logError(const char* msg);
+
+#ifdef __cplusplus
+} // extern C
+#endif