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