summaryrefslogtreecommitdiff
path: root/src/core/apparmor-setup.c
diff options
context:
space:
mode:
authorYmrDtnJu <YmrDtnJu@users.noreply.github.com>2020-05-25 10:46:54 +0200
committerLennart Poettering <lennart@poettering.net>2020-06-09 20:27:47 +0200
commit2ffadd3ceee3abcb339d3ec08a11238794d42d24 (patch)
treeb577229f2694e571fedeabce40f07f597bae5f29 /src/core/apparmor-setup.c
parentd689f0f20aba32fd1b99330f032a6a343d0e2ab5 (diff)
downloadsystemd-2ffadd3ceee3abcb339d3ec08a11238794d42d24.tar.gz
AppArmor: Support for loading a set of pre-compiled profiles at startup time
Let systemd load a set of pre-compiled AppArmor profile files from a policy cache at /etc/apparmor/earlypolicy. Maintenance of that policy cache must be done outside of systemd. After successfully loading the profiles systemd will attempt to change to a profile named systemd. If systemd is already confined in a profile, it will not load any profile files and will not attempt to change it's profile. If anything goes wrong, systemd will only log failures. It will not fail to start.
Diffstat (limited to 'src/core/apparmor-setup.c')
-rw-r--r--src/core/apparmor-setup.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/src/core/apparmor-setup.c b/src/core/apparmor-setup.c
new file mode 100644
index 0000000000..6cba841a6c
--- /dev/null
+++ b/src/core/apparmor-setup.c
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <errno.h>
+#if HAVE_APPARMOR
+# include <sys/apparmor.h>
+#endif
+#include <unistd.h>
+
+#include "apparmor-setup.h"
+#include "apparmor-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "log.h"
+#include "macro.h"
+#include "string-util.h"
+#include "strv.h"
+
+#if HAVE_APPARMOR
+DEFINE_TRIVIAL_CLEANUP_FUNC(aa_policy_cache *, aa_policy_cache_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(aa_features *, aa_features_unref);
+#endif
+
+int mac_apparmor_setup(void) {
+#if HAVE_APPARMOR
+ int r;
+ _cleanup_(aa_policy_cache_unrefp) aa_policy_cache *policy_cache = NULL;
+ _cleanup_(aa_features_unrefp) aa_features *features = NULL;
+ const char *current_file;
+ _cleanup_free_ char *current_profile = NULL, *cache_dir_path = NULL;
+
+ if (!mac_apparmor_use()) {
+ log_debug("AppArmor either 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.
+ */
+ FOREACH_STRING(current_file, "/proc/self/attr/apparmor/current", "/proc/self/attr/current") {
+ r = read_one_line_file(current_file, &current_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
+ break;
+ }
+ 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.");
+ return 0;
+ }
+ if (!streq(current_profile, "unconfined")) {
+ log_debug("We are already confined in an AppArmor profile.");
+ return 0;
+ }
+
+ r = 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");
+ if (!cache_dir_path) {
+ log_debug_errno(errno, "Failed to get the path of the early AppArmor policy cache directory.");
+ 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);
+ 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");
+ return 0;
+ }
+ r = 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);
+ return 0;
+ }
+
+ log_info("Successfully loaded all binary profiles from AppArmor early policy cache at %s.", cache_dir_path);
+
+ r = 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);
+ else
+ log_error_errno(errno, "Failed to change to AppArmor profile 'systemd': %m");
+ return 0;
+ }
+
+ log_info("Changed to AppArmor profile systemd.");
+#endif
+ return 0;
+}