From: Yu Watanabe Date: Wed, 16 Apr 2025 17:39:08 +0000 (+0900) Subject: core/bpf-firewall: replace bpf_firewall_supported() with bpf_program_supported() X-Git-Tag: v258-rc1~653^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ec3c5cfac74e8361a3b0153cc9e8cfdbbcbde0c6;p=thirdparty%2Fsystemd.git core/bpf-firewall: replace bpf_firewall_supported() with bpf_program_supported() 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. --- diff --git a/src/core/bpf-firewall.c b/src/core/bpf-firewall.c index a1e557c420c..428c0c97813 100644 --- a/src/core/bpf-firewall.c +++ b/src/core/bpf-firewall.c @@ -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" : diff --git a/src/core/bpf-firewall.h b/src/core/bpf-firewall.h index f7b72d0ea19..27cbdf857bc 100644 --- a/src/core/bpf-firewall.h +++ b/src/core/bpf-firewall.h @@ -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); diff --git a/src/core/cgroup.c b/src/core/cgroup.c index d58820df838..896db2d647a 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -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) diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index e73a3731f3f..713bd30265c 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -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; } } diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index e718dbc76b9..93270de82a2 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -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; } diff --git a/src/core/socket.c b/src/core/socket.c index 0de430b97ed..af67ac3d06f 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -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) diff --git a/src/test/test-bpf-firewall.c b/src/test/test-bpf-firewall.c index 10bfa52e26b..8ba3a888ecd 100644 --- a/src/test/test-bpf-firewall.c +++ b/src/test/test-bpf-firewall.c @@ -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; }