Merge "bpfloader: pass whole struct Location to loadProg()"
diff --git a/bpfloader/Android.bp b/bpfloader/Android.bp
index 42cb50c..d3428b0 100644
--- a/bpfloader/Android.bp
+++ b/bpfloader/Android.bp
@@ -59,4 +59,11 @@
"timeInState.o"
],
+ product_variables: {
+ debuggable: {
+ required: [
+ "bpfRingbufProg.o",
+ ],
+ },
+ }
}
diff --git a/bpfloader/BpfLoader.cpp b/bpfloader/BpfLoader.cpp
index cdb16f4..313b097 100644
--- a/bpfloader/BpfLoader.cpp
+++ b/bpfloader/BpfLoader.cpp
@@ -207,7 +207,7 @@
return retVal;
}
-void createSysFsBpfSubDir(const char* const prefix) {
+int createSysFsBpfSubDir(const char* const prefix) {
if (*prefix) {
mode_t prevUmask = umask(0);
@@ -217,24 +217,65 @@
errno = 0;
int ret = mkdir(s.c_str(), S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
if (ret && errno != EEXIST) {
- ALOGE("Failed to create directory: %s, ret: %s", s.c_str(), std::strerror(errno));
+ const int err = errno;
+ ALOGE("Failed to create directory: %s, ret: %s", s.c_str(), std::strerror(err));
+ return -err;
}
umask(prevUmask);
}
+ return 0;
+}
+
+// Technically 'value' doesn't need to be newline terminated, but it's best
+// to include a newline to match 'echo "value" > /proc/sys/...foo' behaviour,
+// which is usually how kernel devs test the actual sysctl interfaces.
+int writeProcSysFile(const char *filename, const char *value) {
+ android::base::unique_fd fd(open(filename, O_WRONLY | O_CLOEXEC));
+ if (fd < 0) {
+ const int err = errno;
+ ALOGE("open('%s', O_WRONLY | O_CLOEXEC) -> %s", filename, strerror(err));
+ return -err;
+ }
+ int len = strlen(value);
+ int v = write(fd, value, len);
+ if (v < 0) {
+ const int err = errno;
+ ALOGE("write('%s', '%s', %d) -> %s", filename, value, len, strerror(err));
+ return -err;
+ }
+ if (v != len) {
+ // In practice, due to us only using this for /proc/sys/... files, this can't happen.
+ ALOGE("write('%s', '%s', %d) -> short write [%d]", filename, value, len, v);
+ return -EINVAL;
+ }
+ return 0;
}
int main(int argc, char** argv) {
(void)argc;
android::base::InitLogging(argv, &android::base::KernelLogger);
+ // Linux 5.16-rc1 changed the default to 2 (disabled but changeable), but we need 0 (enabled)
+ // (this writeFile is known to fail on at least 4.19, but always defaults to 0 on pre-5.13,
+ // on 5.13+ it depends on CONFIG_BPF_UNPRIV_DEFAULT_OFF)
+ if (writeProcSysFile("/proc/sys/kernel/unprivileged_bpf_disabled", "0\n") &&
+ android::bpf::isAtLeastKernelVersion(5, 13, 0)) return 1;
+
+ // Enable the eBPF JIT -- but do note that on 64-bit kernels it is likely
+ // already force enabled by the kernel config option BPF_JIT_ALWAYS_ON
+ if (writeProcSysFile("/proc/sys/net/core/bpf_jit_enable", "1\n")) return 1;
+
+ // Enable JIT kallsyms export for privileged users only
+ if (writeProcSysFile("/proc/sys/net/core/bpf_jit_kallsyms", "1\n")) return 1;
+
// This is ugly... but this allows InProcessTethering which runs as system_server,
// instead of as network_stack to access /sys/fs/bpf/tethering, which would otherwise
// (due to genfscon rules) have fs_bpf_tethering selinux context, which is restricted
// to the network_stack process only (which is where out of process tethering runs)
if (isInProcessTethering() && !exists("/sys/fs/bpf/tethering")) {
- createSysFsBpfSubDir(/* /sys/fs/bpf/ */ "net_shared");
- createSysFsBpfSubDir(/* /sys/fs/bpf/ */ "net_shared/tethering");
+ if (createSysFsBpfSubDir(/* /sys/fs/bpf/ */ "net_shared")) return 1;
+ if (createSysFsBpfSubDir(/* /sys/fs/bpf/ */ "net_shared/tethering")) return 1;
/* /sys/fs/bpf/tethering -> net_shared/tethering */
if (symlink("net_shared/tethering", "/sys/fs/bpf/tethering")) {
@@ -248,9 +289,16 @@
// which could otherwise fail with ENOENT during object pinning or renaming,
// due to ordering issues)
for (const auto& location : locations) {
- createSysFsBpfSubDir(location.prefix);
+ if (createSysFsBpfSubDir(location.prefix)) return 1;
}
+ // Note: there's no actual src dir for fs_bpf_loader .o's,
+ // so it is not listed in 'locations[].prefix'.
+ // This is because this is primarily meant for triggering genfscon rules,
+ // and as such this will likely always be the case.
+ // Thus we need to manually create the /sys/fs/bpf/loader subdirectory.
+ if (createSysFsBpfSubDir("loader")) return 1;
+
// Load all ELF objects, create programs and maps, and pin them
for (const auto& location : locations) {
if (loadAllElfObjects(location) != 0) {
diff --git a/bpfloader/bpfloader.rc b/bpfloader/bpfloader.rc
index 1d6248e..b1a6bdb 100644
--- a/bpfloader/bpfloader.rc
+++ b/bpfloader/bpfloader.rc
@@ -15,14 +15,6 @@
# considered to have booted successfully.
#
on load_bpf_programs
- # Linux 5.16-rc1 has changed the default to 2 (disabled but changeable),
- # but we need 0
- write /proc/sys/kernel/unprivileged_bpf_disabled 0
- # Enable the eBPF JIT -- but do note that on 64-bit kernels it is likely
- # already force enabled by the kernel config option BPF_JIT_ALWAYS_ON
- write /proc/sys/net/core/bpf_jit_enable 1
- # Enable JIT kallsyms export for privileged users only
- write /proc/sys/net/core/bpf_jit_kallsyms 1
exec_start bpfloader
service bpfloader /system/bin/bpfloader
diff --git a/libbpf_android/Android.bp b/libbpf_android/Android.bp
index 620f844..1893c6d 100644
--- a/libbpf_android/Android.bp
+++ b/libbpf_android/Android.bp
@@ -26,7 +26,6 @@
name: "libbpf_android",
vendor_available: false,
host_supported: false,
- native_bridge_supported: true,
target: {
android: {
srcs: [
diff --git a/libbpf_android/Loader.cpp b/libbpf_android/Loader.cpp
index 5fe2e10..f1a0123 100644
--- a/libbpf_android/Loader.cpp
+++ b/libbpf_android/Loader.cpp
@@ -30,9 +30,9 @@
#include <sys/wait.h>
#include <unistd.h>
-// This is BpfLoader v0.29
+// This is BpfLoader v0.31
#define BPFLOADER_VERSION_MAJOR 0u
-#define BPFLOADER_VERSION_MINOR 29u
+#define BPFLOADER_VERSION_MINOR 31u
#define BPFLOADER_VERSION ((BPFLOADER_VERSION_MAJOR << 16) | BPFLOADER_VERSION_MINOR)
#include "bpf/BpfUtils.h"
@@ -87,6 +87,7 @@
case domain::netd_readonly: return "fs_bpf_netd_readonly";
case domain::netd_shared: return "fs_bpf_netd_shared";
case domain::vendor: return "fs_bpf_vendor";
+ case domain::loader: return "fs_bpf_loader";
default: return "(unrecognized)";
}
}
@@ -118,6 +119,7 @@
case domain::netd_readonly: return "netd_readonly/";
case domain::netd_shared: return "netd_shared/";
case domain::vendor: return "vendor/";
+ case domain::loader: return "loader/";
default: return "(unrecognized)";
}
};
diff --git a/libbpf_android/include/libbpf_android.h b/libbpf_android/include/libbpf_android.h
index 1856798..7811179 100644
--- a/libbpf_android/include/libbpf_android.h
+++ b/libbpf_android/include/libbpf_android.h
@@ -45,6 +45,7 @@
netd_readonly, // (T+) fs_bpf_netd_readonly /sys/fs/bpf/netd_readonly
netd_shared, // (T+) fs_bpf_netd_shared /sys/fs/bpf/netd_shared
vendor, // (T+) fs_bpf_vendor /sys/fs/bpf/vendor
+ loader, // (U+) fs_bpf_loader /sys/fs/bpf/loader
};
// Note: this does not include domain::unrecognized, but does include domain::unspecified
@@ -57,6 +58,7 @@
domain::netd_readonly,
domain::netd_shared,
domain::vendor,
+ domain::loader,
};
static constexpr bool unrecognized(domain d) {
diff --git a/progs/Android.bp b/progs/Android.bp
index aeb04a7..b044eb0 100644
--- a/progs/Android.bp
+++ b/progs/Android.bp
@@ -26,3 +26,12 @@
name: "bpf_prog_headers",
export_include_dirs: ["include"],
}
+
+bpf {
+ name: "bpfRingbufProg.o",
+ srcs: ["bpfRingbufProg.c"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/progs/bpfRingbufProg.c b/progs/bpfRingbufProg.c
new file mode 100644
index 0000000..99b8345
--- /dev/null
+++ b/progs/bpfRingbufProg.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bpf_helpers.h"
+
+// This can't be easily changed since the program is loaded on boot and may be
+// run against tests at a slightly different version.
+#define TEST_RINGBUF_MAGIC_NUM 12345
+
+// This ring buffer is for testing purposes only.
+DEFINE_BPF_RINGBUF_EXT(test_ringbuf, __u64, 4096, AID_ROOT, AID_ROOT, 0660, "", "", false);
+
+// This program is for test purposes only - it should never be attached to a
+// socket, only executed manually with BPF_PROG_RUN.
+DEFINE_BPF_PROG_KVER("skfilter/ringbuf_test", AID_ROOT, AID_ROOT, test_ringbuf_prog, KVER(5, 8, 0))
+(void* unused_ctx) {
+ __u64* output = bpf_test_ringbuf_reserve();
+ if (output == NULL) return 1;
+
+ (*output) = TEST_RINGBUF_MAGIC_NUM;
+ bpf_test_ringbuf_submit(output);
+
+ return 0;
+}
+
+LICENSE("Apache 2.0");
+CRITICAL("BPF Ringbuf test");