lsm: use atomic in ase we're used multi-threaded

parent d701d729
......@@ -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>
......@@ -25,14 +26,13 @@
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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment