diff --git a/src/core/bpf-restrict-fs.c b/src/core/bpf-restrict-fs.c index 8db05f4db3..f435469c30 100644 --- a/src/core/bpf-restrict-fs.c +++ b/src/core/bpf-restrict-fs.c @@ -30,14 +30,28 @@ static struct restrict_fs_bpf *restrict_fs_bpf_free(struct restrict_fs_bpf *obj) DEFINE_TRIVIAL_CLEANUP_FUNC(struct restrict_fs_bpf *, restrict_fs_bpf_free); -static int prepare_restrict_fs_bpf(struct restrict_fs_bpf **ret_obj) { - _cleanup_(restrict_fs_bpf_freep) struct restrict_fs_bpf *obj = NULL; - _cleanup_close_ int inner_map_fd = -EBADF; +int bpf_restrict_fs_setup(Manager *m) { int r; - assert(ret_obj); + assert(m); - obj = restrict_fs_bpf__open(); + if (!MANAGER_IS_SYSTEM(m)) + return 0; + + r = dlopen_bpf(LOG_WARNING); + if (r < 0) + return r; + + r = lsm_supported("bpf"); + if (r == -ENOPKG) + return log_debug_errno(r, "bpf-restrict-fs: securityfs not mounted, BPF LSM support not available."); + if (r < 0) + return log_warning_errno(r, "bpf-restrict-fs: Can't determine whether the BPF LSM module is used: %m"); + if (r == 0) + return log_info_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "bpf-restrict-fs: BPF LSM hook not enabled in the kernel, BPF LSM not supported."); + + _cleanup_(restrict_fs_bpf_freep) struct restrict_fs_bpf *obj = restrict_fs_bpf__open(); if (!obj) return log_error_errno(errno, "bpf-restrict-fs: Failed to open BPF object: %m"); @@ -49,7 +63,7 @@ static int prepare_restrict_fs_bpf(struct restrict_fs_bpf **ret_obj) { sym_bpf_map__name(obj->maps.cgroup_hash)); /* Dummy map to satisfy the verifier */ - inner_map_fd = compat_bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(uint32_t), sizeof(uint32_t), 128U, NULL); + _cleanup_close_ int inner_map_fd = compat_bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(uint32_t), sizeof(uint32_t), 128U, NULL); if (inner_map_fd < 0) return log_error_errno(errno, "bpf-restrict-fs: Failed to create BPF map: %m"); @@ -63,59 +77,7 @@ static int prepare_restrict_fs_bpf(struct restrict_fs_bpf **ret_obj) { if (r < 0) return log_error_errno(r, "bpf-restrict-fs: Failed to load BPF object: %m"); - *ret_obj = TAKE_PTR(obj); - - return 0; -} - -bool bpf_restrict_fs_supported(bool initialize) { - static int supported = -1; - int r; - - if (supported >= 0) - return supported; - if (!initialize) - return false; - - if (dlopen_bpf(LOG_WARNING) < 0) - return (supported = false); - - r = lsm_supported("bpf"); - if (r == -ENOPKG) { - log_debug_errno(r, "bpf-restrict-fs: securityfs not mounted, BPF LSM support not available."); - return (supported = false); - } - if (r < 0) { - log_warning_errno(r, "bpf-restrict-fs: Can't determine whether the BPF LSM module is used: %m"); - return (supported = false); - } - if (r == 0) { - log_info("bpf-restrict-fs: BPF LSM hook not enabled in the kernel, BPF LSM not supported."); - return (supported = false); - } - - /* We don't try to open/load/attach the BPF program here: that's the expensive part (a real kernel - * verifier pass plus, on the real attach in bpf_restrict_fs_setup(), an LSM link), and doing it - * twice (once here just to throw the result away, once for real in bpf_restrict_fs_setup()) means - * paying that cost twice on every boot for no benefit. If BPF_LSM_MAC attach isn't actually usable - * (e.g. no BPF trampoline support on this architecture/kernel), bpf_restrict_fs_setup()'s own - * attach will fail when it is later called, and that failure is already logged and handled - * gracefully by its caller. */ - return (supported = true); -} - -int bpf_restrict_fs_setup(Manager *m) { - _cleanup_(restrict_fs_bpf_freep) struct restrict_fs_bpf *obj = NULL; - _cleanup_(bpf_link_freep) struct bpf_link *link = NULL; - int r; - - assert(m); - - r = prepare_restrict_fs_bpf(&obj); - if (r < 0) - return r; - - link = sym_bpf_program__attach_lsm(obj->progs.restrict_filesystems); + _cleanup_(bpf_link_freep) struct bpf_link *link = sym_bpf_program__attach_lsm(obj->progs.restrict_filesystems); r = bpf_get_error_translated(link); if (r != 0) return log_error_errno(r, "bpf-restrict-fs: Failed to link '%s' LSM BPF program: %m", @@ -193,10 +155,6 @@ int bpf_restrict_fs_cleanup(Unit *u) { assert(u); assert(u->manager); - /* If we never successfully detected support, there is nothing to clean up. */ - if (!bpf_restrict_fs_supported(/* initialize= */ false)) - return 0; - if (!u->manager->restrict_fs) return 0; @@ -231,11 +189,12 @@ void bpf_restrict_fs_destroy(struct restrict_fs_bpf *prog) { restrict_fs_bpf__destroy(prog); } #else /* ! BPF_FRAMEWORK */ -bool bpf_restrict_fs_supported(bool initialize) { - return false; -} - int bpf_restrict_fs_setup(Manager *m) { + assert(m); + + if (!MANAGER_IS_SYSTEM(m)) + return 0; + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "bpf-restrict-fs: BPF framework is not supported."); } diff --git a/src/core/bpf-restrict-fs.h b/src/core/bpf-restrict-fs.h index dbc017e251..cf7d129ce3 100644 --- a/src/core/bpf-restrict-fs.h +++ b/src/core/bpf-restrict-fs.h @@ -9,7 +9,6 @@ typedef enum FilesystemParseFlags { FILESYSTEM_PARSE_LOG = 1 << 2, } FilesystemParseFlags; -bool bpf_restrict_fs_supported(bool initialize); int bpf_restrict_fs_setup(Manager *m); int bpf_restrict_fs_update(const Set *filesystems, uint64_t cgroup_id, int outer_map_fd, bool allow_list); int bpf_restrict_fs_cleanup(Unit *u); diff --git a/src/core/manager.c b/src/core/manager.c index e82ba36fd5..8f7c5bbed6 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1056,13 +1056,7 @@ int manager_new(RuntimeScope runtime_scope, ManagerTestRunFlags test_run_flags, return r; } -#if HAVE_LIBBPF - if (MANAGER_IS_SYSTEM(m) && bpf_restrict_fs_supported(/* initialize= */ true)) { - r = bpf_restrict_fs_setup(m); - if (r < 0) - log_warning_errno(r, "Failed to setup LSM BPF, ignoring: %m"); - } -#endif + (void) bpf_restrict_fs_setup(m); } if (test_run_flags == 0) { diff --git a/src/test/test-bpf-restrict-fs.c b/src/test/test-bpf-restrict-fs.c index 2eba2a9aa9..7154657f8b 100644 --- a/src/test/test-bpf-restrict-fs.c +++ b/src/test/test-bpf-restrict-fs.c @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "bpf-restrict-fs.h" #include "load-fragment.h" #include "manager.h" #include "process-util.h" @@ -75,9 +74,6 @@ int main(int argc, char *argv[]) { if (!can_memlock()) return log_tests_skipped("Can't use mlock()"); - if (!bpf_restrict_fs_supported(/* initialize= */ true)) - return log_tests_skipped("LSM BPF hooks are not supported"); - r = enter_cgroup_subroot(NULL); if (r == -ENOMEDIUM) return log_tests_skipped("cgroupfs not available"); @@ -96,12 +92,8 @@ int main(int argc, char *argv[]) { return log_tests_skipped_errno(r, "manager_startup"); ASSERT_OK(r); - /* bpf_restrict_fs_supported() above only checks that the BPF LSM hook is enabled in the kernel; it - * doesn't verify that the LSM BPF program managed to actually attach (e.g. some architectures/older - * kernels lack BPF trampoline support). If it didn't, manager_startup() already logged a warning - * and continued without enforcement, so skip here rather than hard-failing the assertions below. */ if (!m->restrict_fs) - return log_tests_skipped("Failed to attach LSM BPF program"); + return log_tests_skipped("LSM BPF hooks are not supported"); /* We need to enable access to the filesystem where the binary is so we * add @common-block and @application */