From 15f9731efc59deb271eb8086d05f532209c8561e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 13 Jun 2024 14:11:28 -0700 Subject: [PATCH] NetBpfLoad: change condition for when we execute platform bpfloader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note that 'true iff U QPR3 or V+' comment is subtle. netbpfload.35rc runs netbpfload as 'root' uid, so V+ is obvious. However, netbpfload.33rc runs netbpfload as 'system' uid, so one would think that this isn't true on T/U. However the U QPR2 and U QPR3 'service bpfloader' actually run platform netbpfload, and the U QPR3 platform netbpfload immediately executes the apex provided netbpfload... Once the apex netbpfload finishes mainline init is considered 'done', and thus we won't (need to) start service mdnsd_netbpfload. As a result even on U QPR3, we never run netbpfload as system uid. Test: TreeHugger Change-Id: I02661dff07c317394a9d8ba3d48e4cb9cd694fd0 Signed-off-by: Maciej Żenczykowski --- netbpfload/NetBpfLoad.cpp | 26 ++++++---- netbpfload/netbpfload.33rc | 10 +--- netd/BpfHandler.cpp | 47 +++++++++++-------- ...id_server_connectivity_ClatCoordinator.cpp | 7 +-- 4 files changed, 47 insertions(+), 43 deletions(-) diff --git a/netbpfload/NetBpfLoad.cpp b/netbpfload/NetBpfLoad.cpp index fefe99bdc9..e9f8e7c972 100644 --- a/netbpfload/NetBpfLoad.cpp +++ b/netbpfload/NetBpfLoad.cpp @@ -254,7 +254,7 @@ static bool isTV() { } static int doLoad(char** argv, char * const envp[]) { - const bool runningAsRoot = !getuid(); + const bool runningAsRoot = !getuid(); // true iff U QPR3 or V+ const int device_api_level = android_get_device_api_level(); const bool isAtLeastT = (device_api_level >= __ANDROID_API_T__); const bool isAtLeastU = (device_api_level >= __ANDROID_API_U__); @@ -456,17 +456,25 @@ static int doLoad(char** argv, char * const envp[]) { return 1; } - if (isAtLeastV) { - ALOGI("done, transferring control to platform bpfloader."); + // leave a flag that we're done + if (createSysFsBpfSubDir("netd_shared/mainline_done")) return 1; - const char * args[] = { platformBpfLoader, NULL, }; - execve(args[0], (char**)args, envp); - ALOGE("FATAL: execve('%s'): %d[%s]", platformBpfLoader, errno, strerror(errno)); - return 1; + // platform bpfloader will only succeed when run as root + if (!runningAsRoot) { + // unreachable on U QPR3+ which always runs netbpfload as root + + ALOGI("mainline done, no need to transfer control to platform bpf loader."); + return 0; } - ALOGI("mainline done!"); - return 0; + // unreachable before U QPR3 + ALOGI("done, transferring control to platform bpfloader."); + + // platform BpfLoader *needs* to run as root + const char * args[] = { platformBpfLoader, NULL, }; + execve(args[0], (char**)args, envp); + ALOGE("FATAL: execve('%s'): %d[%s]", platformBpfLoader, errno, strerror(errno)); + return 1; } } // namespace bpf diff --git a/netbpfload/netbpfload.33rc b/netbpfload/netbpfload.33rc index e13998914a..05f566e131 100644 --- a/netbpfload/netbpfload.33rc +++ b/netbpfload/netbpfload.33rc @@ -1,12 +1,4 @@ -service mdnsd_netbpfload /system/bin/bpfloader - capabilities CHOWN SYS_ADMIN NET_ADMIN - group root graphics network_stack net_admin net_bw_acct net_bw_stats net_raw system - user root - rlimit memlock 1073741824 1073741824 - oneshot - reboot_on_failure reboot,bpfloader-failed - -service bpfloader /apex/com.android.tethering/bin/netbpfload +service mdnsd_netbpfload /apex/com.android.tethering/bin/netbpfload capabilities CHOWN SYS_ADMIN NET_ADMIN group system root graphics network_stack net_admin net_bw_acct net_bw_stats net_raw user system diff --git a/netd/BpfHandler.cpp b/netd/BpfHandler.cpp index 38f4a4ee7a..15a4fefaa2 100644 --- a/netd/BpfHandler.cpp +++ b/netd/BpfHandler.cpp @@ -34,6 +34,7 @@ namespace android { namespace net { using base::unique_fd; +using base::WaitForProperty; using bpf::getSocketCookie; using bpf::retrieveProgram; using netdutils::Status; @@ -140,39 +141,47 @@ BpfHandler::BpfHandler() BpfHandler::BpfHandler(uint32_t perUidLimit, uint32_t totalLimit) : mPerUidStatsEntriesLimit(perUidLimit), mTotalUidStatsEntriesLimit(totalLimit) {} +static bool mainlineNetBpfLoadDone() { + return !access("/sys/fs/bpf/netd_shared/mainline_done", F_OK); +} + // copied with minor changes from waitForProgsLoaded() // p/m/C's staticlibs/native/bpf_headers/include/bpf/WaitForProgsLoaded.h static inline void waitForNetProgsLoaded() { // infinite loop until success with 5/10/20/40/60/60/60... delay for (int delay = 5;; delay *= 2) { if (delay > 60) delay = 60; - if (base::WaitForProperty("init.svc.bpfloader", "stopped", std::chrono::seconds(delay)) - && !access("/sys/fs/bpf/netd_shared", F_OK)) + if (WaitForProperty("init.svc.mdnsd_netbpfload", "stopped", std::chrono::seconds(delay)) + && mainlineNetBpfLoadDone()) return; - ALOGW("Waited %ds for init.svc.bpfloader=stopped, still waiting...", delay); + ALOGW("Waited %ds for init.svc.mdnsd_netbpfload=stopped, still waiting...", delay); } } Status BpfHandler::init(const char* cg2_path) { + // Note: netd *can* be restarted, so this might get called a second time after boot is complete + // at which point we don't need to (and shouldn't) wait for (more importantly start) loading bpf + if (base::GetProperty("bpf.progs_loaded", "") != "1") { - // Make sure BPF programs are loaded before doing anything - ALOGI("Waiting for BPF programs"); - - // TODO: use !modules::sdklevel::IsAtLeastV() once api finalized - if (android_get_device_api_level() < __ANDROID_API_V__) { - waitForNetProgsLoaded(); - ALOGI("Networking BPF programs are loaded"); - - if (!base::SetProperty("ctl.start", "mdnsd_netbpfload")) { - ALOGE("Failed to set property ctl.start=mdnsd_netbpfload, see dmesg for reason."); - abort(); - } - - ALOGI("Waiting for remaining BPF programs"); - } - + // AOSP platform netd & mainline don't need this (at least prior to U QPR3), + // but there could be platform provided (xt_)bpf programs that oem/vendor + // modified netd (which calls us during init) depends on... + ALOGI("Waiting for platform BPF programs"); android::bpf::waitForProgsLoaded(); } + + if (!mainlineNetBpfLoadDone()) { + // we're on < U QPR3 & it's the first time netd is starting up (unless crashlooping) + if (!base::SetProperty("ctl.start", "mdnsd_netbpfload")) { + ALOGE("Failed to set property ctl.start=mdnsd_netbpfload, see dmesg for reason."); + abort(); + } + + ALOGI("Waiting for Networking BPF programs"); + waitForNetProgsLoaded(); + ALOGI("Networking BPF programs are loaded"); + } + ALOGI("BPF programs are loaded"); RETURN_IF_NOT_OK(initPrograms(cg2_path)); diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp index c07d050fff..18a274a12d 100644 --- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp +++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp @@ -114,12 +114,7 @@ static void verifyClatPerms() { V("/sys/fs/bpf", S_IFDIR|S_ISVTX|0777, ROOT, ROOT, "fs_bpf", DIR); - // TODO: use modules::sdklevel::IsAtLeastV() once api finalized - if (android_get_device_api_level() >= __ANDROID_API_V__) { - V("/sys/fs/bpf/net_shared", S_IFDIR|01777, ROOT, ROOT, "fs_bpf_net_shared", DIR); - } else { - V("/sys/fs/bpf/net_shared", S_IFDIR|01777, SYSTEM, SYSTEM, "fs_bpf_net_shared", DIR); - } + V("/sys/fs/bpf/net_shared", S_IFDIR|01777, ROOT, ROOT, "fs_bpf_net_shared", DIR); // pre-U we do not have selinux privs to getattr on bpf maps/progs // so while the below *should* be as listed, we have no way to actually verify