move BPF_CGROUP_INET*_BIND registration into BpfHandler

(in preparation for moving it into netbpfload)

The programs themselves (in bpf_progs/block.c) required a 5.4+ kernel.

We relax this restriction to 4.19+ as we don't have any 5.4 device coverage
(while the pixel 4a 5G / 5 / 5a are all 4.19 devices).

I believe we could relax it further to 4.14+ but Pixel 4/4xl/4a that
would exercise those code paths are EOL and probably have poor to
non existent test coverage, and we cannot do anything for 4.9 T devices
anyway.

Note: on <4.19 kernels (ie. T devices running 4.9/4.14, U running 4.14)
this results in ConnectivityNativeService going from null to initialized
(as the bpf map will exist).

This doesn't hurt as the set/clear port interfaces are only ever
called by vendor code on devices where the kernel doesn't support
the older mechanism.  And even if you call them it will just set/clear
the bits in the bpf bitmap, they just won't actually affect anything.

We could flag the map itself as being 4.19+ as well, but I think
I prefer the no-op map to exist...

Test: TreeHugger
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I1085addd22f4f3b709e1875049633832c5dac836
This commit is contained in:
Maciej Żenczykowski
2023-10-04 21:35:41 +00:00
parent 10da6d4e61
commit 3cb494fd28
4 changed files with 24 additions and 34 deletions

View File

@@ -57,14 +57,18 @@ static inline __always_inline int block_port(struct bpf_sock_addr *ctx) {
return ALLOW; return ALLOW;
} }
DEFINE_BPF_PROG_KVER("bind4/block_port", AID_ROOT, AID_SYSTEM, // the program need to be accessible/loadable by netd (from netd updatable plugin)
bind4_block_port, KVER(5, 4, 0)) #define DEFINE_NETD_RO_BPF_PROG(SECTION_NAME, the_prog, min_kver) \
DEFINE_BPF_PROG_EXT(SECTION_NAME, AID_ROOT, AID_ROOT, the_prog, min_kver, KVER_INF, \
BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, MANDATORY, \
"", "netd_readonly/", LOAD_ON_ENG, LOAD_ON_USER, LOAD_ON_USERDEBUG)
DEFINE_NETD_RO_BPF_PROG("bind4/block_port", bind4_block_port, KVER(4, 19, 0))
(struct bpf_sock_addr *ctx) { (struct bpf_sock_addr *ctx) {
return block_port(ctx); return block_port(ctx);
} }
DEFINE_BPF_PROG_KVER("bind6/block_port", AID_ROOT, AID_SYSTEM, DEFINE_NETD_RO_BPF_PROG("bind6/block_port", bind6_block_port, KVER(4, 19, 0))
bind6_block_port, KVER(5, 4, 0))
(struct bpf_sock_addr *ctx) { (struct bpf_sock_addr *ctx) {
return block_port(ctx); return block_port(ctx);
} }

View File

@@ -130,12 +130,21 @@ static Status initPrograms(const char* cg2_path) {
attachProgramToCgroup(CGROUP_SOCKET_PROG_PATH, cg_fd, BPF_CGROUP_INET_SOCK_CREATE)); attachProgramToCgroup(CGROUP_SOCKET_PROG_PATH, cg_fd, BPF_CGROUP_INET_SOCK_CREATE));
} }
// This should trivially pass, since we just attached up above,
// but BPF_PROG_QUERY is only implemented on 4.19+ kernels.
if (bpf::isAtLeastKernelVersion(4, 19, 0)) { if (bpf::isAtLeastKernelVersion(4, 19, 0)) {
RETURN_IF_NOT_OK(attachProgramToCgroup(
"/sys/fs/bpf/netd_readonly/prog_block_bind4_block_port",
cg_fd, BPF_CGROUP_INET4_BIND));
RETURN_IF_NOT_OK(attachProgramToCgroup(
"/sys/fs/bpf/netd_readonly/prog_block_bind6_block_port",
cg_fd, BPF_CGROUP_INET6_BIND));
// This should trivially pass, since we just attached up above,
// but BPF_PROG_QUERY is only implemented on 4.19+ kernels.
if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET_EGRESS) <= 0) abort(); if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET_EGRESS) <= 0) abort();
if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET_INGRESS) <= 0) abort(); if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET_INGRESS) <= 0) abort();
if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET_SOCK_CREATE) <= 0) abort(); if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET_SOCK_CREATE) <= 0) abort();
if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET4_BIND) <= 0) abort();
if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET6_BIND) <= 0) abort();
} }
return netdutils::status::ok; return netdutils::status::ok;

View File

@@ -46,10 +46,6 @@ public class ConnectivityNativeService extends ConnectivityNative.Stub {
private static final String TAG = ConnectivityNativeService.class.getSimpleName(); private static final String TAG = ConnectivityNativeService.class.getSimpleName();
private static final String CGROUP_PATH = "/sys/fs/cgroup"; private static final String CGROUP_PATH = "/sys/fs/cgroup";
private static final String V4_PROG_PATH =
"/sys/fs/bpf/net_shared/prog_block_bind4_block_port";
private static final String V6_PROG_PATH =
"/sys/fs/bpf/net_shared/prog_block_bind6_block_port";
private static final String BLOCKED_PORTS_MAP_PATH = private static final String BLOCKED_PORTS_MAP_PATH =
"/sys/fs/bpf/net_shared/map_block_blocked_ports_map"; "/sys/fs/bpf/net_shared/map_block_blocked_ports_map";
@@ -95,7 +91,6 @@ public class ConnectivityNativeService extends ConnectivityNative.Stub {
protected ConnectivityNativeService(final Context context, @NonNull Dependencies deps) { protected ConnectivityNativeService(final Context context, @NonNull Dependencies deps) {
mContext = context; mContext = context;
mBpfBlockedPortsMap = deps.getBlockPortsMap(); mBpfBlockedPortsMap = deps.getBlockPortsMap();
attachProgram();
} }
@Override @Override
@@ -155,23 +150,4 @@ public class ConnectivityNativeService extends ConnectivityNative.Stub {
public String getInterfaceHash() { public String getInterfaceHash() {
return this.HASH; return this.HASH;
} }
/**
* Attach BPF program
*/
private void attachProgram() {
try {
BpfUtils.attachProgram(BPF_CGROUP_INET4_BIND, V4_PROG_PATH, CGROUP_PATH, 0);
} catch (IOException e) {
throw new UnsupportedOperationException("Unable to attach to BPF_CGROUP_INET4_BIND: "
+ e);
}
try {
BpfUtils.attachProgram(BPF_CGROUP_INET6_BIND, V6_PROG_PATH, CGROUP_PATH, 0);
} catch (IOException e) {
throw new UnsupportedOperationException("Unable to attach to BPF_CGROUP_INET6_BIND: "
+ e);
}
Log.d(TAG, "Attached BPF_CGROUP_INET4_BIND and BPF_CGROUP_INET6_BIND programs");
}
} }

View File

@@ -40,6 +40,7 @@ using android::modules::sdklevel::IsAtLeastV;
#define TETHERING "/sys/fs/bpf/tethering/" #define TETHERING "/sys/fs/bpf/tethering/"
#define PRIVATE "/sys/fs/bpf/net_private/" #define PRIVATE "/sys/fs/bpf/net_private/"
#define SHARED "/sys/fs/bpf/net_shared/" #define SHARED "/sys/fs/bpf/net_shared/"
#define NETD_RO "/sys/fs/bpf/netd_readonly/"
#define NETD "/sys/fs/bpf/netd_shared/" #define NETD "/sys/fs/bpf/netd_shared/"
class BpfExistenceTest : public ::testing::Test { class BpfExistenceTest : public ::testing::Test {
@@ -119,9 +120,9 @@ static const set<string> MAINLINE_FOR_T_4_14_PLUS = {
}; };
// Provided by *current* mainline module for T+ devices with 5.4+ kernels // Provided by *current* mainline module for T+ devices with 5.4+ kernels
static const set<string> MAINLINE_FOR_T_5_4_PLUS = { static const set<string> MAINLINE_FOR_T_4_19_PLUS = {
SHARED "prog_block_bind4_block_port", NETD_RO "prog_block_bind4_block_port",
SHARED "prog_block_bind6_block_port", NETD_RO "prog_block_bind6_block_port",
}; };
// Provided by *current* mainline module for T+ devices with 5.15+ kernels // Provided by *current* mainline module for T+ devices with 5.15+ kernels
@@ -176,7 +177,7 @@ TEST_F(BpfExistenceTest, TestPrograms) {
// T still only requires Linux Kernel 4.9+. // T still only requires Linux Kernel 4.9+.
DO_EXPECT(IsAtLeastT(), MAINLINE_FOR_T_PLUS); DO_EXPECT(IsAtLeastT(), MAINLINE_FOR_T_PLUS);
DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(4, 14, 0), MAINLINE_FOR_T_4_14_PLUS); DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(4, 14, 0), MAINLINE_FOR_T_4_14_PLUS);
DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(5, 4, 0), MAINLINE_FOR_T_5_4_PLUS); DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(4, 19, 0), MAINLINE_FOR_T_4_19_PLUS);
DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(5, 15, 0), MAINLINE_FOR_T_5_15_PLUS); DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(5, 15, 0), MAINLINE_FOR_T_5_15_PLUS);
// U requires Linux Kernel 4.14+, but nothing (as yet) added or removed in U. // U requires Linux Kernel 4.14+, but nothing (as yet) added or removed in U.