From 03b6caadb63be14ebefec4258085f8a0e73bbeb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 3 Dec 2022 09:38:05 +0000 Subject: bpfloader - move sysctl setting from rc to binary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this allows tightening the sepolicy for 'proc_bpf' in: https://android-review.git.corp.google.com/c/platform/system/sepolicy/+/2323635 'sepolicy - move proc bpf writes from bpfloader.rc to bpfloader binary' While we're at it, this also allows us to actually verify that these sysctls are being successfully set. Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: Ibde9d817b690395e3eb12f6b5acdf3060aca67b9 --- bpfloader/BpfLoader.cpp | 38 ++++++++++++++++++++++++++++++++++++++ bpfloader/bpfloader.rc | 8 -------- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/bpfloader/BpfLoader.cpp b/bpfloader/BpfLoader.cpp index fd261b5..c1be22a 100644 --- a/bpfloader/BpfLoader.cpp +++ b/bpfloader/BpfLoader.cpp @@ -235,10 +235,48 @@ void createSysFsBpfSubDir(const char* const prefix) { } } +// 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 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 -- cgit v1.2.3