diff --git a/src/core/bpf-restrict-fs.c b/src/core/bpf-restrict-fs.c index 8db05f4db3..04b30519f4 100644 --- a/src/core/bpf-restrict-fs.c +++ b/src/core/bpf-restrict-fs.c @@ -21,23 +21,31 @@ #define CGROUP_HASH_SIZE_MAX 2048 -static struct restrict_fs_bpf *restrict_fs_bpf_free(struct restrict_fs_bpf *obj) { - /* restrict_fs_bpf__destroy handles object == NULL case */ - restrict_fs_bpf__destroy(obj); +/* restrict_fs_bpf__destroy handles object == NULL case */ +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(struct restrict_fs_bpf *, restrict_fs_bpf__destroy, restrict_fs_bpf_freep, NULL); - return NULL; -} - -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 +57,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 +71,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 +149,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 +183,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/bpf-restrict-fsaccess.c b/src/core/bpf-restrict-fsaccess.c index e2d5cbf955..3e8714a891 100644 --- a/src/core/bpf-restrict-fsaccess.c +++ b/src/core/bpf-restrict-fsaccess.c @@ -39,10 +39,9 @@ const char* const restrict_fsaccess_link_names[_RESTRICT_FILESYSTEM_ACCESS_LINK_ #if BPF_FRAMEWORK && HAVE_LSM_INTEGRITY_TYPE #include "bpf-util.h" -#include "bpf-link.h" #include "restrict-fsaccess-skel.h" -static struct restrict_fsaccess_bpf *restrict_fsaccess_bpf_free(struct restrict_fsaccess_bpf *obj) { +static struct restrict_fsaccess_bpf* restrict_fsaccess_bpf_free(struct restrict_fsaccess_bpf *obj) { restrict_fsaccess_bpf__destroy(obj); return NULL; } @@ -164,42 +163,6 @@ int bpf_restrict_fsaccess_prepare(struct restrict_fsaccess_bpf **ret) { return 0; } -bool bpf_restrict_fsaccess_supported(void) { - _cleanup_(restrict_fsaccess_bpf_freep) struct restrict_fsaccess_bpf *obj = NULL; - static int supported = -1; - int r; - - if (supported >= 0) - return supported; - if (dlopen_bpf(LOG_WARNING) < 0) - return (supported = false); - - r = lsm_supported("bpf"); - if (r == -ENOPKG) { - log_debug_errno(r, "bpf-restrict-fsaccess: securityfs not mounted, BPF LSM not available."); - return (supported = false); - } - if (r < 0) { - log_warning_errno(r, "bpf-restrict-fsaccess: Can't determine whether the BPF LSM module is used: %m"); - return (supported = false); - } - if (r == 0) { - log_info("bpf-restrict-fsaccess: BPF LSM hook not enabled in the kernel, not supported."); - return (supported = false); - } - - r = bpf_restrict_fsaccess_prepare(&obj); - if (r < 0) - return (supported = false); - - if (!bpf_can_link_lsm_program(obj->progs.restrict_fsaccess_bprm_check)) { - log_warning("bpf-restrict-fsaccess: Failed to link program; assuming BPF LSM is not available."); - return (supported = false); - } - - return (supported = true); -} - /* Partial deserialization (some FDs but not all) is fatal: continuing * would leave enforcement incomplete. */ static int restrict_fsaccess_have_deserialized_fds(Manager *m) { @@ -405,9 +368,18 @@ int bpf_restrict_fsaccess_setup(Manager *m) { } /* Fresh setup: verify BPF LSM is available */ - if (!bpf_restrict_fsaccess_supported()) + r = dlopen_bpf(LOG_WARNING); + if (r < 0) + return r; + + r = lsm_supported("bpf"); + if (r == -ENOPKG) + return log_warning_errno(r, "bpf-restrict-fsaccess: securityfs not mounted, BPF LSM not available."); + if (r < 0) + return log_warning_errno(r, "bpf-restrict-fsaccess: Can't determine whether the BPF LSM module is used: %m"); + if (r == 0) return log_warning_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), - "bpf-restrict-fsaccess: BPF LSM is not available."); + "bpf-restrict-fsaccess: BPF LSM hook not enabled in the kernel, not supported."); /* Require dm-verity signature enforcement */ if (!dm_verity_require_signatures()) @@ -533,10 +505,6 @@ bool dm_verity_require_signatures(void) { return false; } -bool bpf_restrict_fsaccess_supported(void) { - return false; -} - int bpf_restrict_fsaccess_setup(Manager *m) { if (!MANAGER_IS_SYSTEM(m) || m->restrict_filesystem_access <= RESTRICT_FILESYSTEM_ACCESS_NO) return 0; diff --git a/src/core/bpf-restrict-fsaccess.h b/src/core/bpf-restrict-fsaccess.h index cefdcb9ee9..0a8cb45c8f 100644 --- a/src/core/bpf-restrict-fsaccess.h +++ b/src/core/bpf-restrict-fsaccess.h @@ -34,7 +34,6 @@ enum { extern const char* const restrict_fsaccess_link_names[_RESTRICT_FILESYSTEM_ACCESS_LINK_MAX]; bool dm_verity_require_signatures(void); -bool bpf_restrict_fsaccess_supported(void); int bpf_restrict_fsaccess_setup(Manager *m); int bpf_restrict_fsaccess_prepare(struct restrict_fsaccess_bpf **ret); int bpf_restrict_fsaccess_populate_guard(struct restrict_fsaccess_bpf *obj); 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 */ diff --git a/src/test/test-bpf-restrict-fsaccess.c b/src/test/test-bpf-restrict-fsaccess.c index 6df10728eb..df07222478 100644 --- a/src/test/test-bpf-restrict-fsaccess.c +++ b/src/test/test-bpf-restrict-fsaccess.c @@ -24,10 +24,12 @@ #include #include +#include "bpf-link.h" #include "bpf-restrict-fsaccess.h" #include "devnum-util.h" #include "fd-util.h" #include "log.h" +#include "lsm-util.h" #include "string-util.h" #include "tests.h" @@ -161,16 +163,28 @@ static int do_attach(void) { } static int do_check(void) { - if (!bpf_restrict_fsaccess_supported()) { - log_error("BPF LSM is not available"); - return -EOPNOTSUPP; - } + int r; + + r = dlopen_bpf(LOG_WARNING); + if (r < 0) + return r; + + r = lsm_supported("bpf"); + if (r <= 0) + return log_error_errno(r < 0 ? r : EOPNOTSUPP, "BPF LSM is not available: %m"); log_info("BPF LSM: supported"); - if (!dm_verity_require_signatures()) { - log_error("dm-verity require_signatures is not enabled"); - return -ENOKEY; - } + _cleanup_(restrict_fsaccess_bpf_freep) struct restrict_fsaccess_bpf *obj = NULL; + r = bpf_restrict_fsaccess_prepare(&obj); + if (r < 0) + return r; + + if (!bpf_can_link_lsm_program(obj->progs.restrict_fsaccess_bprm_check)) + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "bpf-restrict-fsaccess: Failed to link program."); + + if (!dm_verity_require_signatures()) + return log_error_errno(SYNTHETIC_ERRNO(ENOKEY), "dm-verity require_signatures is not enabled."); log_info("dm-verity require_signatures: enabled"); return 0;