mirror of
git://github.com/lxc/lxc
synced 2025-08-30 13:42:19 +00:00
Merge pull request #2479 from Blub/apparmor-profiles
RFC: Generated Apparmor profiles, namespaces, stacking
This commit is contained in:
commit
400081550b
@ -85,7 +85,6 @@
|
||||
mount options=(rw, nosuid, nodev, noexec, remount) -> /sys/,
|
||||
deny /sys/firmware/efi/efivars/** rwklx,
|
||||
deny /sys/kernel/security/** rwklx,
|
||||
mount options=(move) /sys/fs/cgroup/cgmanager/ -> /sys/fs/cgroup/cgmanager.lower/,
|
||||
mount options=(ro, nosuid, nodev, noexec, remount, strictatime) -> /sys/fs/cgroup/,
|
||||
|
||||
# deny reads from debugfs
|
||||
|
@ -40,5 +40,6 @@
|
||||
pivot_root /usr/lib*/*/lxc/**,
|
||||
|
||||
change_profile -> lxc-*,
|
||||
change_profile -> lxc-**,
|
||||
change_profile -> unconfined,
|
||||
change_profile -> :lxc-*:unconfined,
|
||||
|
@ -9,4 +9,5 @@ profile lxc-container-default-cgns flags=(attach_disconnected,mediate_deleted) {
|
||||
# the newinstance option (but, right now, we don't).
|
||||
deny mount fstype=devpts,
|
||||
mount fstype=cgroup -> /sys/fs/cgroup/**,
|
||||
mount fstype=cgroup2 -> /sys/fs/cgroup/**,
|
||||
}
|
||||
|
@ -11,4 +11,5 @@ profile lxc-container-default-with-nesting flags=(attach_disconnected,mediate_de
|
||||
mount fstype=sysfs -> /var/cache/lxc/**,
|
||||
mount options=(rw,bind),
|
||||
mount fstype=cgroup -> /sys/fs/cgroup/**,
|
||||
mount fstype=cgroup2 -> /sys/fs/cgroup/**,
|
||||
}
|
||||
|
@ -469,6 +469,13 @@ AC_ARG_WITH([cgroup-pattern],
|
||||
[pattern for container cgroups]
|
||||
)], [], [with_cgroup_pattern=['lxc/%n']])
|
||||
|
||||
# The path for the apparmor_parser's cache for generated apparmor profiles
|
||||
AC_ARG_WITH([apparmor-cache-dir],
|
||||
[AC_HELP_STRING(
|
||||
[--with-apparmor-cache-dir=dir],
|
||||
[path for apparmor_parser cache]
|
||||
)], [], [with_apparmor_cache_dir=['${localstatedir}/cache/lxc/apparmor']])
|
||||
|
||||
# Container log path. By default, use $lxcpath.
|
||||
AC_MSG_CHECKING([Whether to place logfiles in container config path])
|
||||
AC_ARG_ENABLE([configpath-log],
|
||||
@ -515,6 +522,7 @@ AS_AC_EXPAND(LXCBINHOOKDIR, "$libexecdir/lxc/hooks")
|
||||
AS_AC_EXPAND(LXCINITDIR, "$libexecdir")
|
||||
AS_AC_EXPAND(LOGPATH, "$with_log_path")
|
||||
AS_AC_EXPAND(RUNTIME_PATH, "$with_runtime_path")
|
||||
AS_AC_EXPAND(APPARMOR_CACHE_DIR, "$with_apparmor_cache_dir")
|
||||
AC_SUBST(DEFAULT_CGROUP_PATTERN, ["$with_cgroup_pattern"])
|
||||
|
||||
# We need the install path so criu knows where to reference the hook scripts.
|
||||
|
@ -174,6 +174,7 @@ AM_CFLAGS = -DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
|
||||
-DDEFAULT_CGROUP_PATTERN=\"$(DEFAULT_CGROUP_PATTERN)\" \
|
||||
-DRUNTIME_PATH=\"$(RUNTIME_PATH)\" \
|
||||
-DSBINDIR=\"$(SBINDIR)\" \
|
||||
-DAPPARMOR_CACHE_DIR=\"$(APPARMOR_CACHE_DIR)\" \
|
||||
-I $(top_srcdir)/src \
|
||||
-I $(top_srcdir)/src/lxc \
|
||||
-I $(top_srcdir)/src/lxc/storage \
|
||||
|
@ -2360,7 +2360,23 @@ static int setup_mount(const struct lxc_conf *conf,
|
||||
return ret;
|
||||
}
|
||||
|
||||
FILE *make_anonymous_mount_file(struct lxc_list *mount)
|
||||
/*
|
||||
* In order for nested containers to be able to mount /proc and /sys they need
|
||||
* to see a "pure" proc and sysfs mount points with nothing mounted on top
|
||||
* (like lxcfs).
|
||||
* For this we provide proc and sysfs in /dev/.lxc/{proc,sys} while using an
|
||||
* apparmor rule to deny access to them. This is mostly for convenience: The
|
||||
* container's root user can mount them anyway and thus has access to the two
|
||||
* file systems. But a non-root user in the container should not be allowed to
|
||||
* access them as a side effect without explicitly allowing it.
|
||||
*/
|
||||
static const char nesting_helpers[] =
|
||||
"proc dev/.lxc/proc proc create=dir,optional\n"
|
||||
"sys dev/.lxc/sys sysfs create=dir,optional\n"
|
||||
;
|
||||
|
||||
FILE *make_anonymous_mount_file(struct lxc_list *mount,
|
||||
bool include_nesting_helpers)
|
||||
{
|
||||
int ret;
|
||||
char *mount_entry;
|
||||
@ -2402,6 +2418,13 @@ FILE *make_anonymous_mount_file(struct lxc_list *mount)
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
if (include_nesting_helpers) {
|
||||
ret = lxc_write_nointr(fd, nesting_helpers,
|
||||
sizeof(nesting_helpers) - 1);
|
||||
if (ret != sizeof(nesting_helpers) - 1)
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
ret = lseek(fd, 0, SEEK_SET);
|
||||
if (ret < 0)
|
||||
goto on_error;
|
||||
@ -2422,7 +2445,7 @@ static int setup_mount_entries(const struct lxc_conf *conf,
|
||||
int ret;
|
||||
FILE *f;
|
||||
|
||||
f = make_anonymous_mount_file(mount);
|
||||
f = make_anonymous_mount_file(mount, conf->lsm_aa_allow_nesting);
|
||||
if (!f)
|
||||
return -1;
|
||||
|
||||
@ -2738,6 +2761,7 @@ struct lxc_conf *lxc_conf_init(void)
|
||||
lxc_list_init(&new->groups);
|
||||
lxc_list_init(&new->state_clients);
|
||||
new->lsm_aa_profile = NULL;
|
||||
lxc_list_init(&new->lsm_aa_raw);
|
||||
new->lsm_se_context = NULL;
|
||||
new->tmp_umount_proc = false;
|
||||
new->tmp_umount_proc = 0;
|
||||
@ -4025,6 +4049,19 @@ void lxc_clear_includes(struct lxc_conf *conf)
|
||||
}
|
||||
}
|
||||
|
||||
int lxc_clear_apparmor_raw(struct lxc_conf *c)
|
||||
{
|
||||
struct lxc_list *it, *next;
|
||||
|
||||
lxc_list_for_each_safe (it, &c->lsm_aa_raw, next) {
|
||||
lxc_list_del(it);
|
||||
free(it->elem);
|
||||
free(it);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lxc_conf_free(struct lxc_conf *conf)
|
||||
{
|
||||
if (!conf)
|
||||
@ -4052,6 +4089,7 @@ void lxc_conf_free(struct lxc_conf *conf)
|
||||
free(conf->syslog);
|
||||
lxc_free_networks(&conf->network);
|
||||
free(conf->lsm_aa_profile);
|
||||
free(conf->lsm_aa_profile_computed);
|
||||
free(conf->lsm_se_context);
|
||||
lxc_seccomp_free(conf);
|
||||
lxc_clear_config_caps(conf);
|
||||
@ -4068,6 +4106,7 @@ void lxc_conf_free(struct lxc_conf *conf)
|
||||
lxc_clear_limits(conf, "lxc.prlimit");
|
||||
lxc_clear_sysctls(conf, "lxc.sysctl");
|
||||
lxc_clear_procs(conf, "lxc.proc");
|
||||
lxc_clear_apparmor_raw(conf);
|
||||
free(conf->cgroup_meta.dir);
|
||||
free(conf->cgroup_meta.controllers);
|
||||
free(conf->shmount.path_host);
|
||||
|
@ -275,7 +275,11 @@ struct lxc_conf {
|
||||
};
|
||||
|
||||
char *lsm_aa_profile;
|
||||
char *lsm_aa_profile_computed;
|
||||
bool lsm_aa_profile_created;
|
||||
unsigned int lsm_aa_allow_nesting;
|
||||
unsigned int lsm_aa_allow_incomplete;
|
||||
struct lxc_list lsm_aa_raw;
|
||||
char *lsm_se_context;
|
||||
bool tmp_umount_proc;
|
||||
char *seccomp; /* filename with the seccomp rules */
|
||||
@ -427,7 +431,8 @@ extern int parse_mntopts(const char *mntopts, unsigned long *mntflags,
|
||||
extern void tmp_proc_unmount(struct lxc_conf *lxc_conf);
|
||||
extern void remount_all_slave(void);
|
||||
extern void suggest_default_idmap(void);
|
||||
extern FILE *make_anonymous_mount_file(struct lxc_list *mount);
|
||||
extern FILE *make_anonymous_mount_file(struct lxc_list *mount,
|
||||
bool include_nesting_helpers);
|
||||
extern struct lxc_list *sort_cgroup_settings(struct lxc_list *cgroup_settings);
|
||||
extern unsigned long add_required_remount_flags(const char *s, const char *d,
|
||||
unsigned long flags);
|
||||
@ -441,5 +446,6 @@ extern int setup_sysctl_parameters(struct lxc_list *sysctls);
|
||||
extern int lxc_clear_sysctls(struct lxc_conf *c, const char *key);
|
||||
extern int setup_proc_filesystem(struct lxc_list *procs, pid_t pid);
|
||||
extern int lxc_clear_procs(struct lxc_conf *c, const char *key);
|
||||
extern int lxc_clear_apparmor_raw(struct lxc_conf *c);
|
||||
|
||||
#endif /* __LXC_CONF_H */
|
||||
|
@ -84,7 +84,9 @@ lxc_log_define(confile, lxc);
|
||||
|
||||
lxc_config_define(autodev);
|
||||
lxc_config_define(apparmor_allow_incomplete);
|
||||
lxc_config_define(apparmor_allow_nesting);
|
||||
lxc_config_define(apparmor_profile);
|
||||
lxc_config_define(apparmor_raw);
|
||||
lxc_config_define(cap_drop);
|
||||
lxc_config_define(cap_keep);
|
||||
lxc_config_define(cgroup_controller);
|
||||
@ -158,6 +160,8 @@ static struct lxc_config_t config[] = {
|
||||
{ "lxc.arch", set_config_personality, get_config_personality, clr_config_personality, },
|
||||
{ "lxc.apparmor.profile", set_config_apparmor_profile, get_config_apparmor_profile, clr_config_apparmor_profile, },
|
||||
{ "lxc.apparmor.allow_incomplete", set_config_apparmor_allow_incomplete, get_config_apparmor_allow_incomplete, clr_config_apparmor_allow_incomplete, },
|
||||
{ "lxc.apparmor.allow_nesting", set_config_apparmor_allow_nesting, get_config_apparmor_allow_nesting, clr_config_apparmor_allow_nesting, },
|
||||
{ "lxc.apparmor.raw", set_config_apparmor_raw, get_config_apparmor_raw, clr_config_apparmor_raw, },
|
||||
{ "lxc.autodev", set_config_autodev, get_config_autodev, clr_config_autodev, },
|
||||
{ "lxc.cap.drop", set_config_cap_drop, get_config_cap_drop, clr_config_cap_drop, },
|
||||
{ "lxc.cap.keep", set_config_cap_keep, get_config_cap_keep, clr_config_cap_keep, },
|
||||
@ -1132,6 +1136,52 @@ static int set_config_apparmor_allow_incomplete(const char *key,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_config_apparmor_allow_nesting(const char *key,
|
||||
const char *value,
|
||||
struct lxc_conf *lxc_conf,
|
||||
void *data)
|
||||
{
|
||||
if (lxc_config_value_empty(value))
|
||||
return clr_config_apparmor_allow_nesting(key, lxc_conf, NULL);
|
||||
|
||||
if (lxc_safe_uint(value, &lxc_conf->lsm_aa_allow_nesting) < 0)
|
||||
return -1;
|
||||
|
||||
if (lxc_conf->lsm_aa_allow_nesting > 1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_config_apparmor_raw(const char *key,
|
||||
const char *value,
|
||||
struct lxc_conf *lxc_conf,
|
||||
void *data)
|
||||
{
|
||||
char *elem;
|
||||
struct lxc_list *list;
|
||||
|
||||
if (lxc_config_value_empty(value))
|
||||
return lxc_clear_apparmor_raw(lxc_conf);
|
||||
|
||||
list = malloc(sizeof(*list));
|
||||
if (!list) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
elem = strdup(value);
|
||||
if (!elem) {
|
||||
free(list);
|
||||
return -1;
|
||||
}
|
||||
list->elem = elem;
|
||||
|
||||
lxc_list_add_tail(&lxc_conf->lsm_aa_raw, list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_config_selinux_context(const char *key, const char *value,
|
||||
struct lxc_conf *lxc_conf, void *data)
|
||||
{
|
||||
@ -3004,6 +3054,34 @@ static int get_config_apparmor_allow_incomplete(const char *key, char *retv,
|
||||
c->lsm_aa_allow_incomplete);
|
||||
}
|
||||
|
||||
static int get_config_apparmor_allow_nesting(const char *key, char *retv,
|
||||
int inlen, struct lxc_conf *c,
|
||||
void *data)
|
||||
{
|
||||
return lxc_get_conf_int(c, retv, inlen,
|
||||
c->lsm_aa_allow_nesting);
|
||||
}
|
||||
|
||||
static int get_config_apparmor_raw(const char *key, char *retv,
|
||||
int inlen, struct lxc_conf *c,
|
||||
void *data)
|
||||
{
|
||||
int len;
|
||||
struct lxc_list *it;
|
||||
int fulllen = 0;
|
||||
|
||||
if (!retv)
|
||||
inlen = 0;
|
||||
else
|
||||
memset(retv, 0, inlen);
|
||||
|
||||
lxc_list_for_each(it, &c->lsm_aa_raw) {
|
||||
strprint(retv, inlen, "%s\n", (char *)it->elem);
|
||||
}
|
||||
|
||||
return fulllen;
|
||||
}
|
||||
|
||||
static int get_config_selinux_context(const char *key, char *retv, int inlen,
|
||||
struct lxc_conf *c, void *data)
|
||||
{
|
||||
@ -3794,6 +3872,21 @@ static inline int clr_config_apparmor_allow_incomplete(const char *key,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int clr_config_apparmor_allow_nesting(const char *key,
|
||||
struct lxc_conf *c,
|
||||
void *data)
|
||||
{
|
||||
c->lsm_aa_allow_nesting = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int clr_config_apparmor_raw(const char *key,
|
||||
struct lxc_conf *c,
|
||||
void *data)
|
||||
{
|
||||
return lxc_clear_apparmor_raw(c);
|
||||
}
|
||||
|
||||
static inline int clr_config_selinux_context(const char *key,
|
||||
struct lxc_conf *c, void *data)
|
||||
{
|
||||
@ -4986,7 +5079,9 @@ int lxc_list_subkeys(struct lxc_conf *conf, const char *key, char *retv,
|
||||
|
||||
if (!strcmp(key, "lxc.apparmor")) {
|
||||
strprint(retv, inlen, "allow_incomplete\n");
|
||||
strprint(retv, inlen, "allow_nesting\n");
|
||||
strprint(retv, inlen, "profile\n");
|
||||
strprint(retv, inlen, "raw\n");
|
||||
} else if (!strcmp(key, "lxc.cgroup")) {
|
||||
strprint(retv, inlen, "dir\n");
|
||||
} else if (!strcmp(key, "lxc.selinux")) {
|
||||
|
@ -378,7 +378,8 @@ static void exec_criu(struct cgroup_ops *cgroup_ops, struct criu_opts *opts)
|
||||
DECLARE_ARG(opts->user->action_script);
|
||||
}
|
||||
|
||||
mnts = make_anonymous_mount_file(&opts->c->lxc_conf->mount_list);
|
||||
mnts = make_anonymous_mount_file(&opts->c->lxc_conf->mount_list,
|
||||
opts->c->lxc_conf->lsm_aa_allow_nesting);
|
||||
if (!mnts)
|
||||
goto err;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -142,18 +142,20 @@ int lsm_process_label_set_at(int label_fd, const char *label, bool on_exec)
|
||||
|
||||
if (on_exec) {
|
||||
ERROR("Changing AppArmor profile on exec not supported");
|
||||
return -EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = strlen(label) + strlen("changeprofile ") + 1;
|
||||
command = malloc(len);
|
||||
if (!command)
|
||||
return -1;
|
||||
goto on_error;
|
||||
|
||||
ret = snprintf(command, len, "changeprofile %s", label);
|
||||
if (ret < 0 || (size_t)ret >= len) {
|
||||
int saved_errno = errno;
|
||||
free(command);
|
||||
return -1;
|
||||
errno = saved_errno;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
ret = lxc_write_nointr(label_fd, command, len - 1);
|
||||
@ -161,9 +163,11 @@ int lsm_process_label_set_at(int label_fd, const char *label, bool on_exec)
|
||||
} else if (strcmp(name, "SELinux") == 0) {
|
||||
ret = lxc_write_nointr(label_fd, label, strlen(label));
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
errno = EINVAL;
|
||||
ret = -1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
on_error:
|
||||
SYSERROR("Failed to set %s label \"%s\"", name, label);
|
||||
return -1;
|
||||
}
|
||||
@ -173,11 +177,37 @@ int lsm_process_label_set_at(int label_fd, const char *label, bool on_exec)
|
||||
}
|
||||
|
||||
int lsm_process_label_set(const char *label, struct lxc_conf *conf,
|
||||
bool use_default, bool on_exec)
|
||||
bool on_exec)
|
||||
{
|
||||
if (!drv) {
|
||||
ERROR("LSM driver not inited");
|
||||
return -1;
|
||||
}
|
||||
return drv->process_label_set(label, conf, use_default, on_exec);
|
||||
return drv->process_label_set(label, conf, on_exec);
|
||||
}
|
||||
|
||||
int lsm_process_prepare(struct lxc_conf *conf, const char *lxcpath)
|
||||
{
|
||||
if (!drv) {
|
||||
ERROR("LSM driver not inited");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!drv->prepare)
|
||||
return 0;
|
||||
|
||||
return drv->prepare(conf, lxcpath);
|
||||
}
|
||||
|
||||
void lsm_process_cleanup(struct lxc_conf *conf, const char *lxcpath)
|
||||
{
|
||||
if (!drv) {
|
||||
ERROR("LSM driver not inited");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!drv->cleanup)
|
||||
return;
|
||||
|
||||
drv->cleanup(conf, lxcpath);
|
||||
}
|
||||
|
@ -38,17 +38,21 @@ struct lsm_drv {
|
||||
int (*enabled)(void);
|
||||
char *(*process_label_get)(pid_t pid);
|
||||
int (*process_label_set)(const char *label, struct lxc_conf *conf,
|
||||
bool use_default, bool on_exec);
|
||||
bool on_exec);
|
||||
int (*prepare)(struct lxc_conf *conf, const char *lxcpath);
|
||||
void (*cleanup)(struct lxc_conf *conf, const char *lxcpath);
|
||||
};
|
||||
|
||||
extern void lsm_init(void);
|
||||
extern int lsm_enabled(void);
|
||||
extern const char *lsm_name(void);
|
||||
extern char *lsm_process_label_get(pid_t pid);
|
||||
extern int lsm_process_prepare(struct lxc_conf *conf, const char *lxcpath);
|
||||
extern int lsm_process_label_set(const char *label, struct lxc_conf *conf,
|
||||
bool use_default, bool on_exec);
|
||||
bool on_exec);
|
||||
extern int lsm_process_label_fd_get(pid_t pid, bool on_exec);
|
||||
extern int lsm_process_label_set_at(int label_fd, const char *label,
|
||||
bool on_exec);
|
||||
extern void lsm_process_cleanup(struct lxc_conf *conf, const char *lxcpath);
|
||||
|
||||
#endif /* __LXC_LSM_H */
|
||||
|
@ -30,7 +30,7 @@ static char *nop_process_label_get(pid_t pid)
|
||||
}
|
||||
|
||||
static int nop_process_label_set(const char *label, struct lxc_conf *conf,
|
||||
bool use_default, bool on_exec)
|
||||
bool on_exec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -75,15 +75,13 @@ static char *selinux_process_label_get(pid_t pid)
|
||||
* Notes: This relies on /proc being available.
|
||||
*/
|
||||
static int selinux_process_label_set(const char *inlabel, struct lxc_conf *conf,
|
||||
bool use_default, bool on_exec)
|
||||
bool on_exec)
|
||||
{
|
||||
int ret;
|
||||
const char *label;
|
||||
|
||||
label = inlabel ? inlabel : conf->lsm_se_context;
|
||||
if (!label) {
|
||||
if (!use_default)
|
||||
return -EINVAL;
|
||||
|
||||
label = DEFAULT_LABEL;
|
||||
}
|
||||
|
@ -863,9 +863,19 @@ int lxc_init(const char *name, struct lxc_handler *handler)
|
||||
}
|
||||
TRACE("Initialized cgroup driver");
|
||||
|
||||
ret = lsm_process_prepare(conf, handler->lxcpath);
|
||||
if (ret < 0) {
|
||||
ERROR("Failed to initialize LSM");
|
||||
goto out_destroy_cgroups;
|
||||
}
|
||||
TRACE("Initialized LSM");
|
||||
|
||||
INFO("Container \"%s\" is initialized", name);
|
||||
return 0;
|
||||
|
||||
out_destroy_cgroups:
|
||||
handler->cgroup_ops->destroy(handler->cgroup_ops, handler);
|
||||
|
||||
out_delete_terminal:
|
||||
lxc_terminal_delete(&handler->conf->console);
|
||||
|
||||
@ -956,6 +966,8 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
|
||||
while (namespace_count--)
|
||||
free(namespaces[namespace_count]);
|
||||
|
||||
lsm_process_cleanup(handler->conf, handler->lxcpath);
|
||||
|
||||
cgroup_ops->destroy(cgroup_ops, handler);
|
||||
cgroup_exit(cgroup_ops);
|
||||
|
||||
@ -1235,7 +1247,7 @@ static int do_start(void *data)
|
||||
}
|
||||
|
||||
/* Set the label to change to when we exec(2) the container's init. */
|
||||
ret = lsm_process_label_set(NULL, handler->conf, 1, 1);
|
||||
ret = lsm_process_label_set(NULL, handler->conf, true);
|
||||
if (ret < 0)
|
||||
goto out_warn_father;
|
||||
|
||||
|
@ -2433,6 +2433,30 @@ int run_command(char *buf, size_t buf_size, int (*child_fn)(void *), void *args)
|
||||
return fret;
|
||||
}
|
||||
|
||||
char *must_concat(const char *first, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *cur, *dest;
|
||||
size_t cur_len, it_len;
|
||||
|
||||
dest = must_copy_string(first);
|
||||
cur_len = it_len = strlen(first);
|
||||
|
||||
va_start(args, first);
|
||||
while ((cur = va_arg(args, char *)) != NULL) {
|
||||
it_len = strlen(cur);
|
||||
|
||||
dest = must_realloc(dest, cur_len + it_len + 1);
|
||||
|
||||
(void)memcpy(dest + cur_len, cur, it_len);
|
||||
cur_len += it_len;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
dest[cur_len] = 0;
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *must_make_path(const char *first, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
@ -568,6 +568,7 @@ extern int run_command(char *buf, size_t buf_size, int (*child_fn)(void *),
|
||||
/* Concatenate all passed-in strings into one path. Do not fail. If any piece
|
||||
* is not prefixed with '/', add a '/'.
|
||||
*/
|
||||
__attribute__((sentinel)) extern char *must_concat(const char *first, ...);
|
||||
__attribute__((sentinel)) extern char *must_make_path(const char *first, ...);
|
||||
__attribute__((sentinel)) extern char *must_append_path(char *first, ...);
|
||||
|
||||
|
@ -81,6 +81,7 @@ if DISTRO_UBUNTU
|
||||
bin_SCRIPTS += \
|
||||
lxc-test-lxc-attach \
|
||||
lxc-test-apparmor-mount \
|
||||
lxc-test-apparmor-generated \
|
||||
lxc-test-checkpoint-restore \
|
||||
lxc-test-snapdeps \
|
||||
lxc-test-symlink \
|
||||
@ -114,6 +115,7 @@ EXTRA_DIST = \
|
||||
lxc-test-rootfs \
|
||||
lxc-test-autostart \
|
||||
lxc-test-apparmor-mount \
|
||||
lxc-test-apparmor-generated \
|
||||
lxc-test-checkpoint-restore \
|
||||
lxc-test-cloneconfig \
|
||||
lxc-test-createconfig \
|
||||
|
84
src/tests/lxc-test-apparmor-generated
Executable file
84
src/tests/lxc-test-apparmor-generated
Executable file
@ -0,0 +1,84 @@
|
||||
#!/bin/sh
|
||||
|
||||
# lxc: linux Container library
|
||||
|
||||
# This is a test script for generated apparmor profiles
|
||||
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
if ! which apparmor_parser >/dev/null 2>&1; then
|
||||
echo 'SKIP: test for generated apparmor profiles: apparmor_parser missing'
|
||||
fi
|
||||
exit 0
|
||||
|
||||
DONE=0
|
||||
KNOWN_RELEASES="precise trusty xenial yakkety zesty"
|
||||
LOGFILE="/tmp/lxc-test-$$.log"
|
||||
cleanup() {
|
||||
lxc-destroy -n $CONTAINER_NAME >/dev/null 2>&1 || true
|
||||
|
||||
if [ $DONE -eq 0 ]; then
|
||||
[ -f "$LOGFILE" ] && cat "$LOGFILE" >&2
|
||||
rm -f "$LOGFILE"
|
||||
echo "FAIL"
|
||||
exit 1
|
||||
fi
|
||||
rm -f "$LOGFILE"
|
||||
echo "PASS"
|
||||
}
|
||||
|
||||
ARCH=i386
|
||||
if type dpkg >/dev/null 2>&1; then
|
||||
ARCH=$(dpkg --print-architecture)
|
||||
fi
|
||||
|
||||
trap cleanup EXIT HUP INT TERM
|
||||
set -eu
|
||||
|
||||
# Create a container
|
||||
CONTAINER_NAME=lxc-test-apparmor-generated
|
||||
|
||||
# default release is trusty, or the systems release if recognized
|
||||
release=trusty
|
||||
if [ -f /etc/lsb-release ]; then
|
||||
. /etc/lsb-release
|
||||
rels=$(ubuntu-distro-info --supported 2>/dev/null) ||
|
||||
rels="$KNOWN_RELEASES"
|
||||
for r in $rels; do
|
||||
[ "$DISTRIB_CODENAME" = "$r" ] && release="$r"
|
||||
done
|
||||
fi
|
||||
|
||||
lxc-create -t download -n $CONTAINER_NAME -B dir -- -d ubuntu -r $release -a $ARCH
|
||||
CONTAINER_PATH=$(dirname $(lxc-info -n $CONTAINER_NAME -c lxc.rootfs.path -H) | sed -e 's/dir://')
|
||||
cp $CONTAINER_PATH/config $CONTAINER_PATH/config.bak
|
||||
|
||||
# Set the profile to be auto-generated
|
||||
echo "lxc.apparmor.profile = generated" >> $CONTAINER_PATH/config
|
||||
|
||||
# Start it
|
||||
lxc-start -n $CONTAINER_NAME -lDEBUG -o "$LOGFILE"
|
||||
lxc-wait -n $CONTAINER_NAME -t 5 -s RUNNING || (echo "Container didn't start" && exit 1)
|
||||
pid=`lxc-info -p -H -n $CONTAINER_NAME`
|
||||
profile=`cat /proc/$pid/attr/current`
|
||||
expected_profile="lxc-${CONTAINER_NAME}_</var/lib/lxc>//&:lxc-${CONTAINER_NAME}_<-var-lib-lxc>:unconfined (enforce)"
|
||||
lxc-stop -n $CONTAINER_NAME -k
|
||||
if [ "x$profile" != "x$expected_profile" ]; then
|
||||
echo "FAIL: container was in profile $profile" >&2
|
||||
echo "expected profile: $expected_profile" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DONE=1
|
@ -23,6 +23,16 @@
|
||||
|
||||
set -e
|
||||
|
||||
# Only run on a normally configured ubuntu lxc system
|
||||
if [ ! -d /sys/class/net/lxcbr0 ]; then
|
||||
echo "lxcbr0 is not configured."
|
||||
exit 1
|
||||
fi
|
||||
if [ "$(id -u)" != "0" ]; then
|
||||
echo "ERROR: Must run as root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f /proc/self/ns/cgroup ]; then
|
||||
default_profile="lxc-container-default-cgns (enforce)"
|
||||
else
|
||||
@ -45,6 +55,7 @@ DONE=0
|
||||
KNOWN_RELEASES="precise trusty xenial yakkety zesty"
|
||||
MOUNTSR=/sys/kernel/security/apparmor/features/mount
|
||||
dnam=`mktemp -d`
|
||||
logfile=`mktemp`
|
||||
cname=`basename $dnam`
|
||||
cleanup() {
|
||||
run_cmd lxc-destroy -f -n $cname || true
|
||||
@ -56,23 +67,24 @@ cleanup() {
|
||||
rm -Rf $HDIR /run/user/$(id -u $TUSER)
|
||||
deluser $TUSER
|
||||
if [ $DONE -eq 0 ]; then
|
||||
echo 'Failed container log:' >&2
|
||||
cat "$logfile" >&2
|
||||
echo 'End log' >&2
|
||||
rm -f "$logfile"
|
||||
echo "FAIL"
|
||||
exit 1
|
||||
fi
|
||||
rm -f "$logfile"
|
||||
echo "PASS"
|
||||
}
|
||||
|
||||
clear_log() {
|
||||
truncate -s0 "$logfile"
|
||||
}
|
||||
|
||||
trap cleanup exit
|
||||
|
||||
# Only run on a normally configured ubuntu lxc system
|
||||
if [ ! -d /sys/class/net/lxcbr0 ]; then
|
||||
echo "lxcbr0 is not configured."
|
||||
exit 1
|
||||
fi
|
||||
if [ "$(id -u)" != "0" ]; then
|
||||
echo "ERROR: Must run as root."
|
||||
exit 1
|
||||
fi
|
||||
chmod 0666 "$logfile"
|
||||
|
||||
# This would be much simpler if we could run it as
|
||||
# root. However, in order to not have the bind mount
|
||||
@ -160,7 +172,7 @@ fi
|
||||
run_cmd lxc-create -t download -n $cname -- -d ubuntu -r $release -a $ARCH
|
||||
|
||||
echo "test default confined container"
|
||||
run_cmd lxc-start -n $cname -d
|
||||
run_cmd lxc-start -n $cname -d -lDEBUG -o "$logfile"
|
||||
run_cmd lxc-wait -n $cname -s RUNNING
|
||||
pid=`run_cmd lxc-info -p -H -n $cname`
|
||||
profile=`cat /proc/$pid/attr/current`
|
||||
@ -169,10 +181,11 @@ if [ "x$profile" != "x${default_profile}" ]; then
|
||||
exit 1
|
||||
fi
|
||||
run_cmd lxc-stop -n $cname -k
|
||||
clear_log
|
||||
|
||||
echo "test regular unconfined container"
|
||||
echo "lxc.apparmor.profile = unconfined" >> $HDIR/.local/share/lxc/$cname/config
|
||||
run_cmd lxc-start -n $cname -d
|
||||
run_cmd lxc-start -n $cname -d -lDEBUG -o "$logfile"
|
||||
run_cmd lxc-wait -n $cname -s RUNNING
|
||||
pid=`run_cmd lxc-info -p -H -n $cname`
|
||||
profile=`cat /proc/$pid/attr/current`
|
||||
@ -181,6 +194,7 @@ if [ "x$profile" != "xunconfined" ]; then
|
||||
exit 1
|
||||
fi
|
||||
run_cmd lxc-stop -n $cname -k
|
||||
clear_log
|
||||
|
||||
echo "masking $MOUNTSR"
|
||||
mount --bind $dnam $MOUNTSR
|
||||
@ -198,7 +212,7 @@ fi
|
||||
|
||||
echo "test regular unconfined container"
|
||||
echo "lxc.apparmor.profile = unconfined" >> $HDIR/.local/share/lxc/$cname/config
|
||||
run_cmd lxc-start -n $cname -d
|
||||
run_cmd lxc-start -n $cname -d -lDEBUG -o "$logfile"
|
||||
run_cmd lxc-wait -n $cname -s RUNNING
|
||||
pid=`run_cmd lxc-info -p -H -n $cname`
|
||||
if [ "$pid" = "-1" ]; then
|
||||
@ -211,11 +225,12 @@ if [ "x$profile" != "xunconfined" ]; then
|
||||
exit 1
|
||||
fi
|
||||
run_cmd lxc-stop -n $cname -k
|
||||
clear_log
|
||||
|
||||
echo "testing override"
|
||||
sed -i '/apparmor.profile/d' $HDIR/.local/share/lxc/$cname/config
|
||||
echo "lxc.apparmor.allow_incomplete = 1" >> $HDIR/.local/share/lxc/$cname/config
|
||||
run_cmd lxc-start -n $cname -d
|
||||
run_cmd lxc-start -n $cname -d -lDEBUG -o "$logfile"
|
||||
run_cmd lxc-wait -n $cname -s RUNNING
|
||||
pid=`run_cmd lxc-info -p -H -n $cname`
|
||||
if [ "$pid" = "-1" ]; then
|
||||
@ -228,5 +243,6 @@ if [ "x$profile" != "x${default_profile}" ]; then
|
||||
exit 1
|
||||
fi
|
||||
run_cmd lxc-stop -n $cname -k
|
||||
clear_log
|
||||
|
||||
DONE=1
|
||||
|
Loading…
x
Reference in New Issue
Block a user