bpf: switch to mainline netbpfload on Android S/SV2
Test: TreeHugger, manually installing tethering apex
(with and without dnsresolver apex) on pixel 6 running S
incl. 'atest bpf_existence_test'
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I63d4b84287e9c98dc0d2a517ac58d3f3ce9d7760
diff --git a/bpf/loader/Android.bp b/bpf/loader/Android.bp
index b08913a..780fe20 100644
--- a/bpf/loader/Android.bp
+++ b/bpf/loader/Android.bp
@@ -56,11 +56,22 @@
installable: false,
}
-// Versioned netbpfload init rc: init system will process it only on api T/33+ devices
+// Versioned netbpfload init rc: init system will process it only on api R/30 S/31 Sv2/32 devices
// Note: R[30] S[31] Sv2[32] T[33] U[34] V[35])
//
// For details of versioned rc files see:
// https://android.googlesource.com/platform/system/core/+/HEAD/init/README.md#versioned-rc-files-within-apexs
+//
+// However, .Xrc versioning doesn't work on S, so we use unversioned, and thus *do* trigger on R,
+// luckily nothing ever uses the new service on R, so you can think of it as being S/Sv2 only
+prebuilt_etc {
+ name: "netbpfload.31rc",
+ src: "netbpfload.31rc",
+ filename: "netbpfload.rc", // intentional: .31rc wouldn't take effect on S
+ installable: false,
+}
+
+// Versioned netbpfload init rc: init system will process it only on api T/33+ devices
prebuilt_etc {
name: "netbpfload.33rc",
src: "netbpfload.33rc",
diff --git a/bpf/loader/NetBpfLoad.cpp b/bpf/loader/NetBpfLoad.cpp
index 9c62e74..bad506f 100644
--- a/bpf/loader/NetBpfLoad.cpp
+++ b/bpf/loader/NetBpfLoad.cpp
@@ -122,6 +122,7 @@
struct Location {
const char* const dir = "";
const char* const prefix = "";
+ const bool t_plus = true;
};
// Returns the build type string (from ro.build.type).
@@ -1216,8 +1217,9 @@
const Location locations[] = {
// S+ Tethering mainline module (network_stack): tether offload
{
- .dir = BPFROOT "/",
+ .dir = BPFROOT "/tethering/",
.prefix = "tethering/",
+ .t_plus = false,
},
// T+ Tethering mainline module (shared with netd & system server)
// netutils_wrapper (for iptables xt_bpf) has access to programs
@@ -1412,6 +1414,13 @@
}
static int doLoad(char** argv, char * const envp[]) {
+ if (!isAtLeastS) {
+ ALOGE("Impossible - not reachable on Android <S.");
+ // for safety, we don't fail, this is a just-in-case workaround
+ // for any possible busted 'optimized' start everything vendor init hacks on R
+ return 0;
+ }
+
const bool runningAsRoot = !getuid(); // true iff U QPR3 or V+
const int first_api_level = GetIntProperty("ro.board.first_api_level", api_level);
@@ -1446,14 +1455,9 @@
logTetheringApexVersion();
- if (!isAtLeastT) {
- ALOGE("Impossible - not reachable on Android <T.");
- return 1;
- }
-
// both S and T require kernel 4.9 (and eBpf support)
- if (isAtLeastT && !isAtLeastKernelVersion(4, 9, 0)) {
- ALOGE("Android T requires kernel 4.9.");
+ if (!isAtLeastKernelVersion(4, 9, 0)) {
+ ALOGE("Android S & T require kernel 4.9.");
return 1;
}
@@ -1622,18 +1626,22 @@
// which could otherwise fail with ENOENT during object pinning or renaming,
// due to ordering issues)
for (const auto& location : locations) {
+ if (location.t_plus && !isAtLeastT) continue;
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;
+ if (isAtLeastT) {
+ // 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 (location.t_plus && !isAtLeastT) continue;
if (loadAllElfObjects(bpfloader_ver, location) != 0) {
ALOGE("=== CRITICAL FAILURE LOADING BPF PROGRAMS FROM %s ===", location.dir);
ALOGE("If this triggers reliably, you're probably missing kernel options or patches.");
@@ -1654,6 +1662,9 @@
return 1;
}
+ // on S we haven't created this subdir yet, but we need it for 'mainline_done' flag below
+ if (!isAtLeastT && createSysFsBpfSubDir("netd_shared")) return 1;
+
// leave a flag that we're done
if (createSysFsBpfSubDir("netd_shared/mainline_done")) return 1;
@@ -1688,7 +1699,12 @@
} // namespace android
int main(int argc, char** argv, char * const envp[]) {
- InitLogging(argv, &KernelLogger);
+ if (android::bpf::isAtLeastT) {
+ InitLogging(argv, &KernelLogger);
+ } else {
+ // S lacks the sepolicy to make non-root uid KernelLogger viable
+ InitLogging(argv);
+ }
if (argc == 2 && !strcmp(argv[1], "done")) {
// we're being re-exec'ed from platform bpfloader to 'finalize' things
diff --git a/bpf/loader/netbpfload.31rc b/bpf/loader/netbpfload.31rc
new file mode 100644
index 0000000..bca7dc8
--- /dev/null
+++ b/bpf/loader/netbpfload.31rc
@@ -0,0 +1,13 @@
+# This file takes effect only on S and Sv2
+# (Note: it does take effect on R as well, but isn't actually used)
+#
+# The service is started from netd's dnsresolver call into ADnsHelper_init()
+# on initial (boot time) startup of netd.
+
+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
+ rlimit memlock 1073741824 1073741824
+ oneshot
+ reboot_on_failure reboot,netbpfload-failed