]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core/bpf-firewall: replace bpf_firewall_supported() with bpf_program_supported()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 16 Apr 2025 17:39:08 +0000 (02:39 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 9 May 2025 15:17:52 +0000 (00:17 +0900)
Note, BPF_PROG_TYPE_CGROUP_SKB is supported since kernel v4.10, and
BPF_F_ALLOW_MULTI and program name is supported since kernel v4.15.
As our baseline on the kernel is v5.4, we can assume that the type,
flag, and naming is supported when bpf_program_supported() succeeds.

src/core/bpf-firewall.c
src/core/bpf-firewall.h
src/core/cgroup.c
src/core/dbus-cgroup.c
src/core/load-fragment.c
src/core/socket.c
src/test/test-bpf-firewall.c

index a1e557c420cf578fec525a9aab6872dfa6bd1141..428c0c97813760397f892e88d2b9048bedbe0367 100644 (file)
@@ -542,7 +542,7 @@ int bpf_firewall_compile(Unit *u) {
         bool ip_allow_any = false, ip_deny_any = false;
         CGroupContext *cc;
         CGroupRuntime *crt;
-        int r, supported;
+        int r;
 
         assert(u);
 
@@ -554,27 +554,12 @@ int bpf_firewall_compile(Unit *u) {
         if (!crt)
                 return -ENOMEM;
 
-        supported = bpf_firewall_supported();
-        if (supported < 0)
-                return supported;
-        if (supported == BPF_FIREWALL_UNSUPPORTED)
+        if (bpf_program_supported() <= 0)
                 return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
                                             "bpf-firewall: BPF firewalling not supported, proceeding without.");
-        if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI && u->type == UNIT_SLICE)
-                /* If BPF_F_ALLOW_MULTI is not supported we don't support any BPF magic on inner nodes (i.e. on slice
-                 * units), since that would mean leaf nodes couldn't do any BPF anymore at all. Under the assumption
-                 * that BPF is more interesting on leaf nodes we hence avoid it on inner nodes in that case. This is
-                 * consistent with old systemd behaviour from before v238, where BPF wasn't supported in inner nodes at
-                 * all, either. */
-                return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
-                                            "bpf-firewall: BPF_F_ALLOW_MULTI is not supported, not doing BPF firewall on slice units.");
 
-        /* If BPF_F_ALLOW_MULTI flag is supported program name is also supported (both were added to v4.15
-         * kernel). */
-        if (supported == BPF_FIREWALL_SUPPORTED_WITH_MULTI) {
-                ingress_name = "sd_fw_ingress";
-                egress_name = "sd_fw_egress";
-        }
+        ingress_name = "sd_fw_ingress";
+        egress_name = "sd_fw_egress";
 
         /* Note that when we compile a new firewall we first flush out the access maps and the BPF programs themselves,
          * but we reuse the accounting maps. That way the firewall in effect always maps to the actual
@@ -646,7 +631,7 @@ static int load_bpf_progs_from_fs_to_set(Unit *u, char **filter_paths, Set **set
 int bpf_firewall_load_custom(Unit *u) {
         CGroupContext *cc;
         CGroupRuntime *crt;
-        int r, supported;
+        int r;
 
         assert(u);
 
@@ -660,13 +645,9 @@ int bpf_firewall_load_custom(Unit *u) {
         if (!(cc->ip_filters_ingress || cc->ip_filters_egress))
                 return 0;
 
-        supported = bpf_firewall_supported();
-        if (supported < 0)
-                return supported;
-
-        if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI)
+        if (bpf_program_supported() <= 0)
                 return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
-                                            "bpf-firewall: BPF_F_ALLOW_MULTI not supported, cannot attach custom BPF programs.");
+                                            "bpf-firewall: BPF firewalling not supported, cannot attach custom BPF programs.");
 
         r = load_bpf_progs_from_fs_to_set(u, cc->ip_filters_ingress, &crt->ip_bpf_custom_ingress);
         if (r < 0)
@@ -702,8 +683,7 @@ int bpf_firewall_install(Unit *u) {
         _cleanup_free_ char *path = NULL;
         CGroupContext *cc;
         CGroupRuntime *crt;
-        int r, supported;
-        uint32_t flags;
+        int r;
 
         assert(u);
 
@@ -718,43 +698,23 @@ int bpf_firewall_install(Unit *u) {
         if (!crt->cgroup_realized)
                 return -EINVAL;
 
-        supported = bpf_firewall_supported();
-        if (supported < 0)
-                return supported;
-        if (supported == BPF_FIREWALL_UNSUPPORTED)
+        if (bpf_program_supported() <= 0)
                 return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
                                             "bpf-firewall: BPF firewalling not supported, proceeding without.");
-        if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI && u->type == UNIT_SLICE)
-                return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
-                                            "bpf-firewall: BPF_F_ALLOW_MULTI not supported, not doing BPF firewall on slice units.");
-        if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI &&
-            (!set_isempty(crt->ip_bpf_custom_ingress) || !set_isempty(crt->ip_bpf_custom_egress)))
-                return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
-                                            "bpf-firewall: BPF_F_ALLOW_MULTI not supported, cannot attach custom BPF programs.");
 
         r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, crt->cgroup_path, NULL, &path);
         if (r < 0)
                 return log_unit_error_errno(u, r, "bpf-firewall: Failed to determine cgroup path: %m");
 
-        flags = supported == BPF_FIREWALL_SUPPORTED_WITH_MULTI ? BPF_F_ALLOW_MULTI : 0;
-
-        if (FLAGS_SET(flags, BPF_F_ALLOW_MULTI)) {
-                /* If we have BPF_F_ALLOW_MULTI, then let's clear the fields, but destroy the programs only
-                 * after attaching the new programs, so that there's no time window where neither program is
-                 * attached. (There will be a program where both are attached, but that's OK, since this is a
-                 * security feature where we rather want to lock down too much than too little */
-                ip_bpf_egress_uninstall = TAKE_PTR(crt->ip_bpf_egress_installed);
-                ip_bpf_ingress_uninstall = TAKE_PTR(crt->ip_bpf_ingress_installed);
-        } else {
-                /* If we don't have BPF_F_ALLOW_MULTI then unref the old BPF programs (which will implicitly
-                 * detach them) right before attaching the new program, to minimize the time window when we
-                 * don't account for IP traffic. */
-                crt->ip_bpf_egress_installed = bpf_program_free(crt->ip_bpf_egress_installed);
-                crt->ip_bpf_ingress_installed = bpf_program_free(crt->ip_bpf_ingress_installed);
-        }
+        /* Let's clear the fields, but destroy the programs only after attaching the new programs, so that
+         * there's no time window where neither program is attached. (There will be a program where both are
+         * attached, but that's OK, since this is a security feature where we rather want to lock down too
+         * much than too little. */
+        ip_bpf_egress_uninstall = TAKE_PTR(crt->ip_bpf_egress_installed);
+        ip_bpf_ingress_uninstall = TAKE_PTR(crt->ip_bpf_ingress_installed);
 
         if (crt->ip_bpf_egress) {
-                r = bpf_program_cgroup_attach(crt->ip_bpf_egress, BPF_CGROUP_INET_EGRESS, path, flags);
+                r = bpf_program_cgroup_attach(crt->ip_bpf_egress, BPF_CGROUP_INET_EGRESS, path, BPF_F_ALLOW_MULTI);
                 if (r < 0)
                         return log_unit_error_errno(u, r,
                                 "bpf-firewall: Attaching egress BPF program to cgroup %s failed: %m", path);
@@ -764,7 +724,7 @@ int bpf_firewall_install(Unit *u) {
         }
 
         if (crt->ip_bpf_ingress) {
-                r = bpf_program_cgroup_attach(crt->ip_bpf_ingress, BPF_CGROUP_INET_INGRESS, path, flags);
+                r = bpf_program_cgroup_attach(crt->ip_bpf_ingress, BPF_CGROUP_INET_INGRESS, path, BPF_F_ALLOW_MULTI);
                 if (r < 0)
                         return log_unit_error_errno(u, r,
                                 "bpf-firewall: Attaching ingress BPF program to cgroup %s failed: %m", path);
@@ -830,118 +790,9 @@ int bpf_firewall_reset_accounting(int map_fd) {
         return bpf_map_update_element(map_fd, &key, &value);
 }
 
-static int bpf_firewall_unsupported_reason = 0;
-
-int bpf_firewall_supported(void) {
-        const struct bpf_insn trivial[] = {
-                BPF_MOV64_IMM(BPF_REG_0, 1),
-                BPF_EXIT_INSN()
-        };
-
-        _cleanup_(bpf_program_freep) BPFProgram *program = NULL;
-        static int supported = -1;
-        union bpf_attr attr;
-        int r;
-
-        /* Checks whether BPF firewalling is supported. For this, we check the following things:
-         *
-         * - the BPF implementation in the kernel supports BPF_PROG_TYPE_CGROUP_SKB programs, which we require
-         * - the BPF implementation in the kernel supports the BPF_PROG_DETACH call, which we require
-         */
-        if (supported >= 0)
-                return supported;
-
-        /* prog_name is NULL since it is supported only starting from v4.15 kernel. */
-        r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, NULL, &program);
-        if (r < 0) {
-                bpf_firewall_unsupported_reason =
-                        log_debug_errno(r, "bpf-firewall: Can't allocate CGROUP SKB BPF program, BPF firewalling is not supported: %m");
-                return supported = BPF_FIREWALL_UNSUPPORTED;
-        }
-
-        r = bpf_program_add_instructions(program, trivial, ELEMENTSOF(trivial));
-        if (r < 0) {
-                bpf_firewall_unsupported_reason =
-                        log_debug_errno(r, "bpf-firewall: Can't add trivial instructions to CGROUP SKB BPF program, BPF firewalling is not supported: %m");
-                return supported = BPF_FIREWALL_UNSUPPORTED;
-        }
-
-        r = bpf_program_load_kernel(program, NULL, 0);
-        if (r < 0) {
-                bpf_firewall_unsupported_reason =
-                        log_debug_errno(r, "bpf-firewall: Can't load kernel CGROUP SKB BPF program, BPF firewalling is not supported: %m");
-                return supported = BPF_FIREWALL_UNSUPPORTED;
-        }
-
-        /* Unfortunately the kernel allows us to create BPF_PROG_TYPE_CGROUP_SKB programs even when CONFIG_CGROUP_BPF
-         * is turned off at kernel compilation time. This sucks of course: why does it allow us to create a cgroup BPF
-         * program if we can't do a thing with it later?
-         *
-         * We detect this case by issuing the BPF_PROG_DETACH bpf() call with invalid file descriptors: if
-         * CONFIG_CGROUP_BPF is turned off, then the call will fail early with EINVAL. If it is turned on the
-         * parameters are validated however, and that'll fail with EBADF then. */
-
-        // FIXME: Clang doesn't 0-pad with structured initialization, causing
-        // the kernel to reject the bpf_attr as invalid. See:
-        // https://github.com/torvalds/linux/blob/v5.9/kernel/bpf/syscall.c#L65
-        // Ideally it should behave like GCC, so that we can remove these workarounds.
-        zero(attr);
-        attr.attach_type = BPF_CGROUP_INET_EGRESS;
-        attr.target_fd = -EBADF;
-        attr.attach_bpf_fd = -EBADF;
-
-        if (bpf(BPF_PROG_DETACH, &attr, sizeof(attr)) < 0) {
-                if (errno != EBADF) {
-                        bpf_firewall_unsupported_reason =
-                                log_debug_errno(errno, "bpf-firewall: Didn't get EBADF from BPF_PROG_DETACH, BPF firewalling is not supported: %m");
-                        return supported = BPF_FIREWALL_UNSUPPORTED;
-                }
-
-                /* YAY! */
-        } else {
-                bpf_firewall_unsupported_reason =
-                        log_debug_errno(SYNTHETIC_ERRNO(EBADE),
-                                        "bpf-firewall: Wut? Kernel accepted our invalid BPF_PROG_DETACH call? "
-                                        "Something is weird, assuming BPF firewalling is broken and hence not supported.");
-                return supported = BPF_FIREWALL_UNSUPPORTED;
-        }
-
-        /* So now we know that the BPF program is generally available, let's see if BPF_F_ALLOW_MULTI is also supported
-         * (which was added in kernel 4.15). We use a similar logic as before, but this time we use the BPF_PROG_ATTACH
-         * bpf() call and the BPF_F_ALLOW_MULTI flags value. Since the flags are checked early in the system call we'll
-         * get EINVAL if it's not supported, and EBADF as before if it is available.
-         * Use probe result as the indicator that program name is also supported since they both were
-         * added in kernel 4.15. */
-
-        zero(attr);
-        attr.attach_type = BPF_CGROUP_INET_EGRESS;
-        attr.target_fd = -EBADF;
-        attr.attach_bpf_fd = -EBADF;
-        attr.attach_flags = BPF_F_ALLOW_MULTI;
-
-        if (bpf(BPF_PROG_ATTACH, &attr, sizeof(attr)) < 0) {
-                if (errno == EBADF) {
-                        log_debug_errno(errno, "bpf-firewall: Got EBADF when using BPF_F_ALLOW_MULTI, which indicates it is supported. Yay!");
-                        return supported = BPF_FIREWALL_SUPPORTED_WITH_MULTI;
-                }
-
-                if (errno == EINVAL)
-                        log_debug_errno(errno, "bpf-firewall: Got EINVAL error when using BPF_F_ALLOW_MULTI, which indicates it's not supported.");
-                else
-                        log_debug_errno(errno, "bpf-firewall: Got unexpected error when using BPF_F_ALLOW_MULTI, assuming it's not supported: %m");
-
-                return supported = BPF_FIREWALL_SUPPORTED;
-        } else {
-                bpf_firewall_unsupported_reason =
-                        log_debug_errno(SYNTHETIC_ERRNO(EBADE),
-                                        "bpf-firewall: Wut? Kernel accepted our invalid BPF_PROG_ATTACH+BPF_F_ALLOW_MULTI call? "
-                                        "Something is weird, assuming BPF firewalling is broken and hence not supported.");
-                return supported = BPF_FIREWALL_UNSUPPORTED;
-        }
-}
-
 void emit_bpf_firewall_warning(Unit *u) {
         static bool warned = false;
+        int r;
 
         assert(u);
         assert(u->manager);
@@ -949,9 +800,12 @@ void emit_bpf_firewall_warning(Unit *u) {
         if (warned || MANAGER_IS_TEST_RUN(u->manager))
                 return;
 
-        bool quiet = ERRNO_IS_PRIVILEGE(bpf_firewall_unsupported_reason) && detect_container() > 0;
+        r = bpf_program_supported();
+        assert(r < 0);
+
+        bool quiet = ERRNO_IS_NEG_PRIVILEGE(r) && detect_container() > 0;
 
-        log_unit_full_errno(u, quiet ? LOG_DEBUG : LOG_WARNING, bpf_firewall_unsupported_reason,
+        log_unit_full_errno(u, quiet ? LOG_DEBUG : LOG_WARNING, r,
                             "unit configures an IP firewall, but %s.\n"
                             "(This warning is only shown for the first unit using IP firewalling.)",
                             getuid() != 0 ? "not running as root" :
index f7b72d0ea193936204e2dc3641879d575c03ca6a..27cbdf857bc60c7aed10d7a5c143a33703d5c58f 100644 (file)
@@ -6,14 +6,6 @@
 #include "cgroup.h"
 #include "unit.h"
 
-enum {
-        BPF_FIREWALL_UNSUPPORTED          = 0,
-        BPF_FIREWALL_SUPPORTED            = 1,
-        BPF_FIREWALL_SUPPORTED_WITH_MULTI = 2,
-};
-
-int bpf_firewall_supported(void);
-
 int bpf_firewall_compile(Unit *u);
 int bpf_firewall_install(Unit *u);
 int bpf_firewall_load_custom(Unit *u);
index d58820df838c94f71254daddffd016c7e4e14f98..896db2d647ac62fc22eee7b5317a0f29c3db35b1 100644 (file)
@@ -3259,12 +3259,10 @@ static int cg_bpf_mask_supported(CGroupMask *ret) {
         CGroupMask mask = 0;
         int r;
 
-        /* BPF-based firewall */
-        r = bpf_firewall_supported();
-        if (r < 0)
-                return r;
-        if (r > 0)
-                mask |= CGROUP_MASK_BPF_FIREWALL;
+        /* BPF-based firewall and pinned foreign prog */
+        if (bpf_program_supported() > 0)
+                mask |= CGROUP_MASK_BPF_FIREWALL |
+                        CGROUP_MASK_BPF_FOREIGN;
 
         /* BPF-based device access control */
         r = bpf_devices_supported();
@@ -3273,10 +3271,6 @@ static int cg_bpf_mask_supported(CGroupMask *ret) {
         if (r > 0)
                 mask |= CGROUP_MASK_BPF_DEVICES;
 
-        /* BPF pinned prog */
-        if (bpf_program_supported() > 0)
-                mask |= CGROUP_MASK_BPF_FOREIGN;
-
         /* BPF-based bind{4|6} hooks */
         r = bpf_socket_bind_supported();
         if (r < 0)
index e73a3731f3fe79fbd6c052c466613c8da805ce74..713bd30265c41348cde3ab80b1a6a266533f5c59 100644 (file)
@@ -635,18 +635,13 @@ static int bus_cgroup_set_transient_property(
 
                         unit_write_setting(u, flags, name, buf);
 
-                        if (*filters) {
-                                r = bpf_firewall_supported();
-                                if (r < 0)
-                                        return r;
-                                if (r != BPF_FIREWALL_SUPPORTED_WITH_MULTI) {
-                                        static bool warned = false;
+                        if (*filters && bpf_program_supported() <= 0) {
+                                static bool warned = false;
 
-                                        log_full(warned ? LOG_DEBUG : LOG_WARNING,
-                                                 "Transient unit %s configures an IP firewall with BPF, but the local system does not support BPF/cgroup firewalling with multiple filters.\n"
-                                                 "Starting this unit will fail! (This warning is only shown for the first started transient unit using IP firewalling.)", u->id);
-                                        warned = true;
-                                }
+                                log_full(warned ? LOG_DEBUG : LOG_WARNING,
+                                         "Transient unit %s configures an IP firewall with BPF, but the local system does not support BPF/cgroup firewalling with multiple filters.\n"
+                                         "Starting this unit will fail! (This warning is only shown for the first started transient unit using IP firewalling.)", u->id);
+                                warned = true;
                         }
                 }
 
index e718dbc76b935c944f668a0ccf1ce668ada8e24c..93270de82a2c172763dd5a3792fa5bcad2d7611a 100644 (file)
@@ -5712,15 +5712,12 @@ int config_parse_ip_filter_bpf_progs(
         if (r < 0)
                 return log_oom();
 
-        r = bpf_firewall_supported();
-        if (r < 0)
-                return r;
-        if (r != BPF_FIREWALL_SUPPORTED_WITH_MULTI) {
+        if (bpf_program_supported() <= 0) {
                 static bool warned = false;
 
-                log_full(warned ? LOG_DEBUG : LOG_WARNING,
-                         "File %s:%u configures an IP firewall with BPF programs (%s=%s), but the local system does not support BPF/cgroup based firewalling with multiple filters.\n"
-                         "Starting this unit will fail! (This warning is only shown for the first loaded unit using IP firewalling.)", filename, line, lvalue, rvalue);
+                log_syntax(unit, warned ? LOG_DEBUG : LOG_WARNING, filename, line, 0,
+                           "Configures an IP firewall with BPF programs (%s=%s), but the local system does not support BPF/cgroup based firewalling with multiple filters. "
+                           "Starting this unit will fail! (This warning is only shown for the first loaded unit using IP firewalling.)", lvalue, rvalue);
 
                 warned = true;
         }
index 0de430b97ed3bc47f6eb77c5ed6538aca015e287..af67ac3d06f3e0b74305e18a29303dcb08bcc6cd 100644 (file)
@@ -1477,9 +1477,7 @@ static int socket_address_listen_do(
                 log_unit_error_errno(u, error, fmt, strna(_t));  \
         })
 
-static int fork_needed(const SocketAddress *address, Socket *s) {
-        int r;
-
+static bool fork_needed(const SocketAddress *address, Socket *s) {
         assert(address);
         assert(s);
 
@@ -1493,13 +1491,9 @@ static int fork_needed(const SocketAddress *address, Socket *s) {
                         if (nft_set->source == NFT_SET_SOURCE_CGROUP)
                                 return true;
 
-        if (IN_SET(address->sockaddr.sa.sa_family, AF_INET, AF_INET6)) {
-                r = bpf_firewall_supported();
-                if (r < 0)
-                        return r;
-                if (r != BPF_FIREWALL_UNSUPPORTED) /* If BPF firewalling isn't supported anyway — there's no point in this forking complexity */
-                        return true;
-        }
+        if (IN_SET(address->sockaddr.sa.sa_family, AF_INET, AF_INET6) &&
+            bpf_program_supported() > 0) /* If BPF firewalling isn't supported anyway — there's no point in this forking complexity */
+                return true;
 
         return exec_needs_network_namespace(&s->exec_context);
 }
@@ -1521,10 +1515,7 @@ static int socket_address_listen_in_cgroup(
          * the socket is actually properly attached to the unit's cgroup for the purpose of BPF filtering and
          * such. */
 
-        r = fork_needed(address, s);
-        if (r < 0)
-                return r;
-        if (r == 0) {
+        if (!fork_needed(address, s)) {
                 /* Shortcut things... */
                 fd = socket_address_listen_do(s, address, label);
                 if (fd < 0)
@@ -3030,10 +3021,7 @@ static int socket_accept_in_cgroup(Socket *s, SocketPort *p, int fd) {
         if (!IN_SET(p->address.sockaddr.sa.sa_family, AF_INET, AF_INET6))
                 goto shortcut;
 
-        r = bpf_firewall_supported();
-        if (r < 0)
-                return r;
-        if (r == BPF_FIREWALL_UNSUPPORTED)
+        if (bpf_program_supported() <= 0)
                 goto shortcut;
 
         if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
index 10bfa52e26bb97b1cd2d4bd2dfd8bf8d0cec5205..8ba3a888ecd1af79de694a5bd8e9d63578d64c7f 100644 (file)
@@ -31,7 +31,6 @@ int main(int argc, char *argv[]) {
         struct rlimit rl;
         int r;
         union bpf_attr attr;
-        bool test_custom_filter = false;
         const char *test_prog = "/sys/fs/bpf/test-dropper";
 
         test_setup_logging(LOG_DEBUG);
@@ -39,6 +38,11 @@ int main(int argc, char *argv[]) {
         if (detect_container() > 0)
                 return log_tests_skipped("test-bpf-firewall fails inside LXC and Docker containers: https://github.com/systemd/systemd/issues/9666");
 
+        r = bpf_program_supported();
+        if (r < 0)
+                return log_tests_skipped_errno(r, "BPF firewalling not supported");
+        ASSERT_TRUE(r);
+
         ASSERT_OK(getrlimit(RLIMIT_MEMLOCK, &rl));
         rl.rlim_cur = rl.rlim_max = MAX(rl.rlim_max, CAN_MEMLOCK_SIZE);
         (void) setrlimit(RLIMIT_MEMLOCK, &rl);
@@ -65,34 +69,17 @@ int main(int argc, char *argv[]) {
         r = bpf_program_add_instructions(p, exit_insn, ELEMENTSOF(exit_insn));
         ASSERT_EQ(r, 0);
 
-        r = bpf_firewall_supported();
-        if (r == BPF_FIREWALL_UNSUPPORTED)
-                return log_tests_skipped("BPF firewalling not supported");
-        ASSERT_GT(r, 0);
-
-        if (r == BPF_FIREWALL_SUPPORTED_WITH_MULTI) {
-                log_notice("BPF firewalling with BPF_F_ALLOW_MULTI supported. Yay!");
-                test_custom_filter = true;
-        } else
-                log_notice("BPF firewalling (though without BPF_F_ALLOW_MULTI) supported. Good.");
-
         r = bpf_program_load_kernel(p, log_buf, ELEMENTSOF(log_buf));
         ASSERT_OK(r);
 
-        if (test_custom_filter) {
-                zero(attr);
-                attr.pathname = PTR_TO_UINT64(test_prog);
-                attr.bpf_fd = p->kernel_fd;
-                attr.file_flags = 0;
+        zero(attr);
+        attr.pathname = PTR_TO_UINT64(test_prog);
+        attr.bpf_fd = p->kernel_fd;
+        attr.file_flags = 0;
 
-                (void) unlink(test_prog);
+        (void) unlink(test_prog);
 
-                r = bpf(BPF_OBJ_PIN, &attr, sizeof(attr));
-                if (r < 0) {
-                        log_warning_errno(errno, "BPF object pinning failed, will not run custom filter test: %m");
-                        test_custom_filter = false;
-                }
-        }
+        ASSERT_OK(bpf(BPF_OBJ_PIN, &attr, sizeof(attr)));
 
         p = bpf_program_free(p);
 
@@ -192,31 +179,30 @@ int main(int argc, char *argv[]) {
         assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->exec_status.code != CLD_EXITED ||
                   SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->exec_status.status != EXIT_SUCCESS);
 
-        if (test_custom_filter) {
-                assert_se(u = unit_new(m, sizeof(Service)));
-                assert_se(unit_add_name(u, "custom-filter.service") == 0);
-                assert_se(cc = unit_get_cgroup_context(u));
-                u->perpetual = true;
+        /* testing custom filter */
+        assert_se(u = unit_new(m, sizeof(Service)));
+        assert_se(unit_add_name(u, "custom-filter.service") == 0);
+        assert_se(cc = unit_get_cgroup_context(u));
+        u->perpetual = true;
 
-                cc->ip_accounting = true;
+        cc->ip_accounting = true;
 
-                assert_se(config_parse_ip_filter_bpf_progs(u->id, "filename", 1, "Service", 1, "IPIngressFilterPath", 0, test_prog, &cc->ip_filters_ingress, u) == 0);
-                assert_se(config_parse_exec(u->id, "filename", 1, "Service", 1, "ExecStart", SERVICE_EXEC_START, "-/bin/ping -c 1 127.0.0.1 -W 5", SERVICE(u)->exec_command, u) == 0);
+        assert_se(config_parse_ip_filter_bpf_progs(u->id, "filename", 1, "Service", 1, "IPIngressFilterPath", 0, test_prog, &cc->ip_filters_ingress, u) == 0);
+        assert_se(config_parse_exec(u->id, "filename", 1, "Service", 1, "ExecStart", SERVICE_EXEC_START, "-/bin/ping -c 1 127.0.0.1 -W 5", SERVICE(u)->exec_command, u) == 0);
 
-                SERVICE(u)->type = SERVICE_ONESHOT;
-                u->load_state = UNIT_LOADED;
+        SERVICE(u)->type = SERVICE_ONESHOT;
+        u->load_state = UNIT_LOADED;
 
-                ASSERT_OK(unit_start(u, NULL));
+        ASSERT_OK(unit_start(u, NULL));
 
-                while (!IN_SET(SERVICE(u)->state, SERVICE_DEAD, SERVICE_FAILED))
-                        assert_se(sd_event_run(m->event, UINT64_MAX) >= 0);
+        while (!IN_SET(SERVICE(u)->state, SERVICE_DEAD, SERVICE_FAILED))
+                assert_se(sd_event_run(m->event, UINT64_MAX) >= 0);
 
-                assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->exec_status.code != CLD_EXITED ||
-                          SERVICE(u)->exec_command[SERVICE_EXEC_START]->exec_status.status != EXIT_SUCCESS);
+        assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->exec_status.code != CLD_EXITED ||
+                  SERVICE(u)->exec_command[SERVICE_EXEC_START]->exec_status.status != EXIT_SUCCESS);
 
-                (void) unlink(test_prog);
-                assert_se(SERVICE(u)->state == SERVICE_DEAD);
-        }
+        (void) unlink(test_prog);
+        assert_se(SERVICE(u)->state == SERVICE_DEAD);
 
         return 0;
 }