]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
lsm: use atomic in ase we're used multi-threaded 3517/head
authorChristian Brauner <christian.brauner@ubuntu.com>
Tue, 11 Aug 2020 08:32:01 +0000 (10:32 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Tue, 11 Aug 2020 08:32:01 +0000 (10:32 +0200)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/lsm/apparmor.c

index 533c043c02c6cd091714c6e18f94c173cc5ce3ac..c4fce1ee6c21cf658ad1956236a2e24deca581bf 100644 (file)
@@ -4,6 +4,7 @@
 #define _GNU_SOURCE 1
 #endif
 #include <errno.h>
+#include <stdatomic.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/mount.h>
 lxc_log_define(apparmor, lsm);
 
 /* set by lsm_apparmor_ops_init if true */
-static int aa_enabled = 0;
-static bool aa_parser_available = false;
-static bool aa_supports_unix = false;
-static bool aa_can_stack = false;
-static bool aa_is_stacked = false;
-static bool aa_admin = false;
-
-static int mount_features_enabled = 0;
+static atomic_int aa_enabled ;
+static atomic_int aa_parser_available = -1;
+static atomic_int aa_supports_unix;
+static atomic_int aa_can_stack;
+static atomic_int aa_is_stacked;
+static atomic_int aa_admin;
+static atomic_int mount_features_enabled;
 
 #define AA_DEF_PROFILE "lxc-container-default"
 #define AA_DEF_PROFILE_CGNS "lxc-container-default-cgns"
@@ -375,7 +375,7 @@ static const char AA_PROFILE_UNPRIVILEGED[] =
 
 static bool check_mount_feature_enabled(void)
 {
-       return mount_features_enabled == 1;
+       return atomic_load(&mount_features_enabled);
 }
 
 static void load_mount_features_enabled(void)
@@ -385,13 +385,13 @@ static void load_mount_features_enabled(void)
 
        ret = stat(AA_MOUNT_RESTR, &statbuf);
        if (ret == 0)
-               mount_features_enabled = 1;
+               atomic_store(&mount_features_enabled, 1);
 }
 
 /* aa_getcon is not working right now.  Use our hand-rolled version below */
 static int apparmor_enabled(void)
 {
-       FILE *fin;
+       __do_fclose FILE *fin = NULL;
        char e;
        int ret;
 
@@ -399,7 +399,6 @@ static int apparmor_enabled(void)
        if (!fin)
                return 0;
        ret = fscanf(fin, "%c", &e);
-       fclose(fin);
        if (ret == 1 && e == 'Y') {
                load_mount_features_enabled();
                return 1;
@@ -545,14 +544,17 @@ static inline char *apparmor_namespace(const char *ctname, const char *lxcpath)
  */
 static bool check_apparmor_parser_version()
 {
+       int major = 0, minor = 0, micro = 0, ret = 0;
        struct lxc_popen_FILE *parserpipe;
        int rc;
-       int major = 0, minor = 0, micro = 0;
+
+       if (atomic_load(&aa_parser_available) >= 0)
+               return false;
 
        parserpipe = lxc_popen("apparmor_parser --version");
        if (!parserpipe) {
                fprintf(stderr, "Failed to run check for apparmor_parser\n");
-               return false;
+               goto out;
        }
 
        rc = fscanf(parserpipe->f, "AppArmor parser version %d.%d.%d", &major, &minor, &micro);
@@ -562,24 +564,27 @@ static bool check_apparmor_parser_version()
                 * lxc_popen executed failed to find the apparmor_parser binary.
                 * See the TODO comment above for details.
                 */
-               return false;
+               goto out;
        }
 
        rc = lxc_pclose(parserpipe);
        if (rc < 0) {
                fprintf(stderr, "Error waiting for child process\n");
-               return false;
+               goto out;
        }
        if (rc != 0) {
                fprintf(stderr, "'apparmor_parser --version' executed with an error status\n");
-               return false;
+               goto out;
        }
 
-       aa_supports_unix = (major > 2) ||
-                          (major == 2 && minor > 10) ||
-                          (major == 2 && minor == 10 && micro >= 95);
+       if ((major > 2) || (major == 2 && minor > 10) || (major == 2 && minor == 10 && micro >= 95))
+               atomic_store(&aa_supports_unix, 1);
 
-       return true;
+       ret = 1;
+
+out:
+       atomic_store(&aa_parser_available, ret);
+       return ret == 1;
 }
 
 static bool file_is_yes(const char *path)
@@ -744,7 +749,7 @@ static char *get_apparmor_profile_content(struct lxc_conf *conf, const char *lxc
 
        append_all_remount_rules(&profile, &size);
 
-       if (aa_supports_unix)
+       if (atomic_load(&aa_supports_unix))
                must_append_sized(&profile, &size, AA_PROFILE_UNIX_SOCKETS,
                                  STRARRAYLEN(AA_PROFILE_UNIX_SOCKETS));
 
@@ -752,7 +757,7 @@ static char *get_apparmor_profile_content(struct lxc_conf *conf, const char *lxc
                must_append_sized(&profile, &size, AA_PROFILE_CGROUP_NAMESPACES,
                                  STRARRAYLEN(AA_PROFILE_CGROUP_NAMESPACES));
 
-       if (aa_can_stack && !aa_is_stacked) {
+       if (atomic_load(&aa_can_stack) && !atomic_load(&aa_is_stacked)) {
                char *namespace, *temp;
 
                must_append_sized(&profile, &size, AA_PROFILE_STACKING_BASE,
@@ -775,7 +780,7 @@ static char *get_apparmor_profile_content(struct lxc_conf *conf, const char *lxc
                must_append_sized(&profile, &size, AA_PROFILE_NESTING_BASE,
                                  STRARRAYLEN(AA_PROFILE_NESTING_BASE));
 
-               if (!aa_can_stack || aa_is_stacked) {
+               if (!atomic_load(&aa_can_stack) || atomic_load(&aa_is_stacked)) {
                        char *temp;
 
                        temp = must_concat(NULL, "  change_profile -> \"",
@@ -836,7 +841,7 @@ static bool make_apparmor_namespace(struct lxc_conf *conf, const char *lxcpath)
 {
        char *path;
 
-       if (!aa_can_stack || aa_is_stacked)
+       if (!atomic_load(&aa_can_stack) || atomic_load(&aa_is_stacked))
                return true;
 
        path = make_apparmor_namespace_path(conf->name, lxcpath);
@@ -1021,7 +1026,7 @@ out_ok:
  */
 static void apparmor_cleanup(struct lxc_conf *conf, const char *lxcpath)
 {
-       if (!aa_admin)
+       if (!atomic_load(&aa_admin))
                return;
 
        if (!conf->lsm_aa_profile_created)
@@ -1039,7 +1044,7 @@ static int apparmor_prepare(struct lxc_conf *conf, const char *lxcpath)
        const char *label;
        char *curlabel = NULL, *genlabel = NULL;
 
-       if (!aa_enabled) {
+       if (!atomic_load(&aa_enabled)) {
                ERROR("AppArmor not enabled");
                return -1;
        }
@@ -1054,7 +1059,7 @@ static int apparmor_prepare(struct lxc_conf *conf, const char *lxcpath)
        }
 
        if (label && strcmp(label, AA_GENERATED) == 0) {
-               if (!aa_parser_available) {
+               if (!check_apparmor_parser_version()) {
                        ERROR("Cannot use generated profile: apparmor_parser not available");
                        goto out;
                }
@@ -1071,7 +1076,7 @@ static int apparmor_prepare(struct lxc_conf *conf, const char *lxcpath)
                        goto out;
                }
 
-               if (aa_can_stack && !aa_is_stacked) {
+               if (atomic_load(&aa_can_stack) && !atomic_load(&aa_is_stacked)) {
                        char *namespace = apparmor_namespace(conf->name, lxcpath);
                        size_t llen = strlen(genlabel);
                        must_append_sized(&genlabel, &llen, "//&:", STRARRAYLEN("//&:"));
@@ -1085,7 +1090,7 @@ static int apparmor_prepare(struct lxc_conf *conf, const char *lxcpath)
 
        curlabel = apparmor_process_label_get(lxc_raw_getpid());
 
-       if (!aa_can_stack && aa_needs_transition(curlabel)) {
+       if (!atomic_load(&aa_can_stack) && aa_needs_transition(curlabel)) {
                /* we're already confined, and stacking isn't supported */
 
                if (!label || strcmp(curlabel, label) == 0) {
@@ -1196,7 +1201,7 @@ static int apparmor_process_label_set(const char *inlabel, struct lxc_conf *conf
        pid_t tid;
        const char *label;
 
-       if (!aa_enabled) {
+       if (!atomic_load(&aa_enabled)) {
                ERROR("AppArmor not enabled");
                return -1;
        }
@@ -1250,19 +1255,18 @@ static struct lsm_ops apparmor_ops = {
 const struct lsm_ops *lsm_apparmor_ops_init(void)
 {
        bool have_mac_admin = false;
+       bool can_stack, is_stacked;
 
        if (!apparmor_enabled())
                return NULL;
 
-       /* We only support generated profiles when apparmor_parser is usable */
-       if (!check_apparmor_parser_version())
-               goto out;
-
-       aa_parser_available = true;
-
-       aa_can_stack = apparmor_can_stack();
-       if (aa_can_stack)
-               aa_is_stacked = file_is_yes("/sys/kernel/security/apparmor/.ns_stacked");
+       can_stack = apparmor_can_stack();
+       if (can_stack) {
+               atomic_store(&aa_can_stack, 1);
+               is_stacked = file_is_yes("/sys/kernel/security/apparmor/.ns_stacked");
+               if (is_stacked)
+                       atomic_store(&aa_is_stacked, 1);
+       }
 
        #if HAVE_LIBCAP
        have_mac_admin = lxc_proc_cap_is_set(CAP_SETGID, CAP_EFFECTIVE);
@@ -1270,12 +1274,11 @@ const struct lsm_ops *lsm_apparmor_ops_init(void)
 
        if (!have_mac_admin)
                WARN("Per-container AppArmor profiles are disabled because the mac_admin capability is missing");
-       else if (am_host_unpriv() && !aa_is_stacked)
+       else if (am_host_unpriv() && !atomic_load(&aa_is_stacked))
                WARN("Per-container AppArmor profiles are disabled because LXC is running in an unprivileged container without stacking");
        else
-               aa_admin = true;
+               atomic_store(&aa_admin, 1);
 
-out:
-       aa_enabled = 1;
+       atomic_store(&aa_enabled, 1);
        return &apparmor_ops;
 }