#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"
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)
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;
if (!fin)
return 0;
ret = fscanf(fin, "%c", &e);
- fclose(fin);
if (ret == 1 && e == 'Y') {
load_mount_features_enabled();
return 1;
*/
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, µ);
* 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)
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));
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,
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 -> \"",
{
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);
*/
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)
const char *label;
char *curlabel = NULL, *genlabel = NULL;
- if (!aa_enabled) {
+ if (!atomic_load(&aa_enabled)) {
ERROR("AppArmor not enabled");
return -1;
}
}
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;
}
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("//&:"));
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) {
pid_t tid;
const char *label;
- if (!aa_enabled) {
+ if (!atomic_load(&aa_enabled)) {
ERROR("AppArmor not enabled");
return -1;
}
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);
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;
}