From: Mike Yuan Date: Sun, 7 Jul 2024 17:35:40 +0000 (+0200) Subject: core: dlopen()'ify libapparmor X-Git-Tag: v258-rc1~1279 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=384949f7dee164c2c3cfd78f94a5f27b61fb7c28;p=thirdparty%2Fsystemd.git core: dlopen()'ify libapparmor In Arch Linux we currently have a half-baked apparmor support, in particular we cannot link systemd to libapparmor for service context integration, since that will pull apparmor into base system. Hence, let's turn this into a dlopen dep. Ref: https://gitlab.archlinux.org/archlinux/packaging/packages/systemd/-/issues/22 --- diff --git a/meson.build b/meson.build index d38f6ef20f9..e87c8ea2ecd 100644 --- a/meson.build +++ b/meson.build @@ -1220,6 +1220,7 @@ libapparmor = dependency('libapparmor', version : '>= 2.13', required : get_option('apparmor')) conf.set10('HAVE_APPARMOR', libapparmor.found()) +libapparmor_cflags = libapparmor.partial_dependency(includes: true, compile_args: true) have = get_option('smack') and get_option('smack-run-label') != '' conf.set10('HAVE_SMACK_RUN_LABEL', have) diff --git a/src/core/apparmor-setup.c b/src/core/apparmor-setup.c index 3426a103588..a9621995cab 100644 --- a/src/core/apparmor-setup.c +++ b/src/core/apparmor-setup.c @@ -1,13 +1,11 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include -#if HAVE_APPARMOR -# include -#endif #include #include "apparmor-setup.h" #include "apparmor-util.h" +#include "errno-util.h" #include "fd-util.h" #include "fileio.h" #include "log.h" @@ -15,39 +13,35 @@ #include "string-util.h" #include "strv.h" -#if HAVE_APPARMOR -DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(aa_policy_cache *, aa_policy_cache_unref, NULL); -DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(aa_features *, aa_features_unref, NULL); -#endif - int mac_apparmor_setup(void) { #if HAVE_APPARMOR - _cleanup_(aa_policy_cache_unrefp) aa_policy_cache *policy_cache = NULL; - _cleanup_(aa_features_unrefp) aa_features *features = NULL; + _cleanup_(sym_aa_policy_cache_unrefp) aa_policy_cache *policy_cache = NULL; + _cleanup_(sym_aa_features_unrefp) aa_features *features = NULL; _cleanup_free_ char *current_profile = NULL, *cache_dir_path = NULL; int r; if (!mac_apparmor_use()) { - log_debug("AppArmor either not supported by the kernel or disabled."); + log_debug("Skipping AppArmor initialization: not supported by the kernel or disabled."); return 0; } - /* To enable LSM stacking a patch to the kernel is proposed to create a - * per-LSM subdirectory to distinguish between the LSMs. Therefore, we - * read the file from the LSM specific directory first and only if that - * fails the one from the generic directory. - */ + r = dlopen_libapparmor(); + if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) + return 0; + if (r < 0) + return log_error_errno(r, "Failed to load libapparmor: %m"); + + /* To honor LSM stacking, check per-LSM subdirectory first, and then the generic one as fallback. */ FOREACH_STRING(current_file, "/proc/self/attr/apparmor/current", "/proc/self/attr/current") { r = read_one_line_file(current_file, ¤t_profile); - if (r == -ENOENT) - continue; - else if (r < 0) - log_warning_errno(r, "Failed to read current AppArmor profile from file %s, ignoring: %m", current_file); - else + if (r >= 0) break; + if (r != -ENOENT) + log_warning_errno(r, "Failed to read current AppArmor profile from '%s', ignoring: %m", + current_file); } if (!current_profile) { - log_warning("Failed to get the current AppArmor profile of systemd from /proc/self/attr/apparmor/current or /proc/self/attr/current, ignoring."); + log_warning("Failed to get the current AppArmor profile of our own process, ignoring."); return 0; } if (!streq(current_profile, "unconfined")) { @@ -55,39 +49,47 @@ int mac_apparmor_setup(void) { return 0; } - r = aa_features_new_from_kernel(&features); + r = sym_aa_features_new_from_kernel(&features); if (r < 0) { log_warning_errno(errno, "Failed to get the AppArmor feature set from the kernel, ignoring: %m"); return 0; } - cache_dir_path = aa_policy_cache_dir_path_preview(features, AT_FDCWD, "/etc/apparmor/earlypolicy"); + + cache_dir_path = sym_aa_policy_cache_dir_path_preview(features, AT_FDCWD, "/etc/apparmor/earlypolicy"); if (!cache_dir_path) { - log_debug_errno(errno, "Failed to get the path of the early AppArmor policy cache directory."); + log_debug_errno(errno, "Failed to get the path of the early AppArmor policy cache directory, ignoring: %m"); return 0; } /* aa_policy_cache_new will internally use the same path as aa_policy_cache_dir_path_preview has returned. */ - r = aa_policy_cache_new(&policy_cache, features, AT_FDCWD, "/etc/apparmor/earlypolicy", 0); + r = sym_aa_policy_cache_new(&policy_cache, features, AT_FDCWD, "/etc/apparmor/earlypolicy", 0); if (r < 0) { - if (errno == ENOENT) { - log_debug_errno(errno, "The early AppArmor policy cache directory %s does not exist.", cache_dir_path); - return 0; - } - log_warning_errno(errno, "Failed to create a new AppArmor policy cache, ignoring: %m"); + if (errno == ENOENT) + log_debug_errno(errno, + "The early AppArmor policy cache directory '%s' does not exist.", + cache_dir_path); + else + log_warning_errno(errno, "Failed to create a new AppArmor policy cache, ignoring: %m"); return 0; } - r = aa_policy_cache_replace_all(policy_cache, NULL); + + r = sym_aa_policy_cache_replace_all(policy_cache, NULL); if (r < 0) { - log_warning_errno(errno, "Failed to load the profiles from the early AppArmor policy cache directory %s, ignoring: %m", cache_dir_path); + log_warning_errno(errno, + "Failed to load the profiles from the early AppArmor policy cache directory '%s', ignoring: %m", + cache_dir_path); return 0; } - log_info("Successfully loaded all binary profiles from AppArmor early policy cache at %s.", cache_dir_path); + log_info("Successfully loaded all binary profiles from AppArmor early policy cache (%s).", cache_dir_path); - r = aa_change_profile("systemd"); + r = sym_aa_change_profile("systemd"); if (r < 0) { if (errno == ENOENT) - log_debug_errno(errno, "Failed to change to AppArmor profile 'systemd'. Please ensure that one of the binary profile files in policy cache directory %s contains a profile with that name.", cache_dir_path); + log_debug_errno(errno, + "Failed to change to AppArmor profile 'systemd'.\n" + "Please ensure that one of the binary profile files in policy cache directory '%s' contains a profile with that name.", + cache_dir_path); else log_error_errno(errno, "Failed to change to AppArmor profile 'systemd': %m"); return 0; diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index f0ab3637add..2cfff50afc1 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -11,15 +11,9 @@ #include #endif -#if HAVE_APPARMOR -#include -#endif - #include "sd-messages.h" -#if HAVE_APPARMOR #include "apparmor-util.h" -#endif #include "argv-util.h" #include "ask-password-api.h" #include "barrier.h" @@ -5069,7 +5063,12 @@ int exec_invoke( use_smack = mac_smack_use(); #endif #if HAVE_APPARMOR - use_apparmor = mac_apparmor_use(); + if (mac_apparmor_use()) { + r = dlopen_libapparmor(); + if (r < 0 && !ERRNO_IS_NEG_NOT_SUPPORTED(r)) + log_warning_errno(r, "Failed to load libapparmor, ignoring: %m"); + use_apparmor = r >= 0; + } #endif } @@ -5547,7 +5546,7 @@ int exec_invoke( #if HAVE_APPARMOR if (use_apparmor && context->apparmor_profile) { - r = aa_change_onexec(context->apparmor_profile); + r = ASSERT_PTR(sym_aa_change_onexec)(context->apparmor_profile); if (r < 0 && !context->apparmor_profile_ignore) { *exit_status = EXIT_APPARMOR_PROFILE; return log_exec_error_errno(context, diff --git a/src/core/meson.build b/src/core/meson.build index 84cade9ae75..2d51e30e9ba 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -178,7 +178,7 @@ executables += [ libshared, ], 'dependencies' : [ - libapparmor, + libapparmor_cflags, libkmod_cflags, libseccomp, libselinux, @@ -191,7 +191,7 @@ executables += [ 'include_directories' : core_includes, 'link_with' : executor_libs, 'dependencies' : [ - libapparmor, + libapparmor_cflags, libpam, libseccomp, libselinux, diff --git a/src/shared/apparmor-util.c b/src/shared/apparmor-util.c index 68e1c557c0c..a040ea7a892 100644 --- a/src/shared/apparmor-util.c +++ b/src/shared/apparmor-util.c @@ -7,6 +7,39 @@ #include "fileio.h" #include "parse-util.h" +#if HAVE_APPARMOR +static void *libapparmor_dl = NULL; + +DLSYM_PROTOTYPE(aa_change_onexec) = NULL; +DLSYM_PROTOTYPE(aa_change_profile) = NULL; +DLSYM_PROTOTYPE(aa_features_new_from_kernel) = NULL; +DLSYM_PROTOTYPE(aa_features_unref) = NULL; +DLSYM_PROTOTYPE(aa_policy_cache_dir_path_preview) = NULL; +DLSYM_PROTOTYPE(aa_policy_cache_new) = NULL; +DLSYM_PROTOTYPE(aa_policy_cache_replace_all) = NULL; +DLSYM_PROTOTYPE(aa_policy_cache_unref) = NULL; + +int dlopen_libapparmor(void) { + ELF_NOTE_DLOPEN("apparmor", + "Support for AppArmor policies", + ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED, + "libapparmor.so.1"); + + return dlopen_many_sym_or_warn( + &libapparmor_dl, + "libapparmor.so.1", + LOG_DEBUG, + DLSYM_ARG(aa_change_onexec), + DLSYM_ARG(aa_change_profile), + DLSYM_ARG(aa_features_new_from_kernel), + DLSYM_ARG(aa_features_unref), + DLSYM_ARG(aa_policy_cache_dir_path_preview), + DLSYM_ARG(aa_policy_cache_new), + DLSYM_ARG(aa_policy_cache_replace_all), + DLSYM_ARG(aa_policy_cache_unref)); +} +#endif + bool mac_apparmor_use(void) { static int cached_use = -1; diff --git a/src/shared/apparmor-util.h b/src/shared/apparmor-util.h index 8007aeb6957..d19c903536a 100644 --- a/src/shared/apparmor-util.h +++ b/src/shared/apparmor-util.h @@ -3,4 +3,28 @@ #include +#include "dlfcn-util.h" + +#if HAVE_APPARMOR +# include + +extern DLSYM_PROTOTYPE(aa_change_onexec); +extern DLSYM_PROTOTYPE(aa_change_profile); +extern DLSYM_PROTOTYPE(aa_features_new_from_kernel); +extern DLSYM_PROTOTYPE(aa_features_unref); +extern DLSYM_PROTOTYPE(aa_policy_cache_dir_path_preview); +extern DLSYM_PROTOTYPE(aa_policy_cache_new); +extern DLSYM_PROTOTYPE(aa_policy_cache_replace_all); +extern DLSYM_PROTOTYPE(aa_policy_cache_unref); + +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(aa_features*, sym_aa_features_unref, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(aa_policy_cache*, sym_aa_policy_cache_unref, NULL); + +int dlopen_libapparmor(void); +#else +static inline int dlopen_libapparmor(void) { + return -EOPNOTSUPP; +} +#endif + bool mac_apparmor_use(void); diff --git a/src/test/test-dlopen-so.c b/src/test/test-dlopen-so.c index d38dff182af..6d56c19b89d 100644 --- a/src/test/test-dlopen-so.c +++ b/src/test/test-dlopen-so.c @@ -3,6 +3,7 @@ #include #include +#include "apparmor-util.h" #include "bpf-dlopen.h" #include "compress.h" #include "cryptsetup-util.h" @@ -98,6 +99,10 @@ static int run(int argc, char **argv) { assert_se(dlopen_libkmod() >= 0); #endif +#if HAVE_APPARMOR + assert_se(dlopen_libapparmor() >= 0); +#endif + return 0; }