Commit 9958532b by Serge Hallyn Committed by Stéphane Graber

attach: join apparmor profile

This patch enables lxc-attach to join the profile of the container it is attaching to. Builds/runs fine with apparmor enabled and disabled. Export new aa_get_profile(), and use it for attach_apparmor, but also handle profile names longer than 100 chars in lxc_start apparmor support. Signed-off-by: 's avatarSerge Hallyn <serge.hallyn@ubuntu.com> Acked-by: 's avatarStéphane Graber <stgraber@ubuntu.com>
parent c5427d7d
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <sys/types.h> #include <sys/types.h>
...@@ -16,21 +17,58 @@ lxc_log_define(lxc_apparmor, lxc); ...@@ -16,21 +17,58 @@ lxc_log_define(lxc_apparmor, lxc);
#define AA_MOUNT_RESTR "/sys/kernel/security/apparmor/features/mount/mask" #define AA_MOUNT_RESTR "/sys/kernel/security/apparmor/features/mount/mask"
#define AA_ENABLED_FILE "/sys/module/apparmor/parameters/enabled" #define AA_ENABLED_FILE "/sys/module/apparmor/parameters/enabled"
static int aa_am_unconfined(void)
/* caller must free the returned profile */
extern char *aa_get_profile(pid_t pid)
{ {
char path[100], *space;
int ret; int ret;
char path[100], p[100]; char *buf = NULL;
sprintf(path, "/proc/%d/attr/current", getpid()); int sz = 0;
FILE *f = fopen(path, "r"); FILE *f;
if (!f)
return 0; ret = snprintf(path, 100, "/proc/%d/attr/current", pid);
ret = fscanf(f, "%99s", p); if (ret < 0 || ret >= 100) {
ERROR("path name too long");
return NULL;
}
again:
f = fopen(path, "r");
if (!f) {
SYSERROR("opening %s\n", path);
return NULL;
}
sz += 1024;
buf = realloc(buf, sz);
if (!buf) {
ERROR("out of memory");
fclose(f);
return NULL;
}
ret = fread(buf, 1, sz, f);
fclose(f); fclose(f);
if (ret < 1) if (ret >= sz)
return 0; goto again;
if (strcmp(p, "unconfined") == 0) if (ret < 0) {
return 1; ERROR("reading %s\n", path);
return 0; free(buf);
return NULL;
}
space = index(buf, ' ');
if (space)
*space = '\0';
return buf;
}
static int aa_am_unconfined(void)
{
char *p = aa_get_profile(getpid());
int ret = 0;
if (!p || strcmp(p, "unconfined") == 0)
ret = 1;
if (p)
free(p);
return ret;
} }
/* aa_getcon is not working right now. Use our hand-rolled version below */ /* aa_getcon is not working right now. Use our hand-rolled version below */
...@@ -61,36 +99,57 @@ extern void apparmor_handler_init(struct lxc_handler *handler) ...@@ -61,36 +99,57 @@ extern void apparmor_handler_init(struct lxc_handler *handler)
} }
#define AA_DEF_PROFILE "lxc-container-default" #define AA_DEF_PROFILE "lxc-container-default"
extern int apparmor_load(struct lxc_handler *handler)
extern int do_apparmor_load(int aa_enabled, char *aa_profile,
int umount_proc, int dropprivs)
{ {
if (!handler->aa_enabled) { if (!aa_enabled) {
INFO("apparmor not enabled"); INFO("apparmor not enabled");
return 0; return 0;
} }
INFO("setting up apparmor"); INFO("setting up apparmor");
if (!handler->conf->aa_profile) if (!aa_profile)
handler->conf->aa_profile = AA_DEF_PROFILE; aa_profile = AA_DEF_PROFILE;
if (strcmp(handler->conf->aa_profile, "unconfined") == 0 && if (strcmp(aa_profile, "unconfined") == 0 && !dropprivs && aa_am_unconfined()) {
aa_am_unconfined()) {
INFO("apparmor profile unchanged"); INFO("apparmor profile unchanged");
return 0; return 0;
} }
//if (aa_change_onexec(handler->conf->aa_profile) < 0) { //if (aa_change_onexec(aa_profile) < 0) {
if (aa_change_profile(handler->conf->aa_profile) < 0) { if (aa_change_profile(aa_profile) < 0) {
SYSERROR("failed to change apparmor profile to %s", handler->conf->aa_profile); SYSERROR("failed to change apparmor profile to %s", aa_profile);
return -1; return -1;
} }
if (handler->conf->lsm_umount_proc == 1) if (umount_proc == 1)
umount("/proc"); umount("/proc");
INFO("changed apparmor profile to %s", handler->conf->aa_profile); INFO("changed apparmor profile to %s", aa_profile);
return 0; return 0;
} }
extern int apparmor_load(struct lxc_handler *handler)
{
if (!handler->conf->aa_profile)
handler->conf->aa_profile = AA_DEF_PROFILE;
return do_apparmor_load(handler->aa_enabled,
handler->conf->aa_profile,
handler->conf->lsm_umount_proc, 0);
}
extern int attach_apparmor(char *profile)
{
if (!profile)
return 0;
if (!check_apparmor_enabled())
return 0;
if (strcmp(profile, "unconfined") == 0)
return 0;
return do_apparmor_load(1, profile, 0, 1);
}
/* /*
* this will likely move to a generic lsm.c, as selinux and smack will both * this will likely move to a generic lsm.c, as selinux and smack will both
* also want proc mounted in the container so as to transition * also want proc mounted in the container so as to transition
......
...@@ -3,16 +3,34 @@ ...@@ -3,16 +3,34 @@
struct lxc_handler; struct lxc_handler;
/*
* apparmor_handler_init is really just a wrapper around check_apparmor_enabled
* to allow us to keep from having #ifdef APPARMOR in start.c
*/
extern void apparmor_handler_init(struct lxc_handler *handler);
#if HAVE_APPARMOR #if HAVE_APPARMOR
extern char *aa_get_profile(pid_t pid);
extern int do_apparmor_load(int aa_enabled, char *aa_profile,
int umount_proc, int dropprivs);
extern int apparmor_load(struct lxc_handler *handler); extern int apparmor_load(struct lxc_handler *handler);
extern int attach_apparmor(char *profile);
extern int lsm_mount_proc_if_needed(char *root_src, char *rootfs_tgt); extern int lsm_mount_proc_if_needed(char *root_src, char *rootfs_tgt);
extern void apparmor_handler_init(struct lxc_handler *handler);
#else #else
static inline char *aa_get_profile(pid_t pid) {
return NULL;
}
static inline int do_apparmor_load(int aa_enabled, char *aa_profile,
int umount_proc, int dropprivs) {
return 0;
}
static inline int attach_apparmor(char *profile) {
return 0;
}
static inline int apparmor_load(struct lxc_handler *handler) { static inline int apparmor_load(struct lxc_handler *handler) {
return 0; return 0;
} }
static inline int lsm_mount_proc_if_needed(char *root_src, char *rootfs_tgt) { static inline int lsm_mount_proc_if_needed(char *root_src, char *rootfs_tgt) {
return 0; return 0;
} }
extern void apparmor_handler_init(struct lxc_handler *handler);
#endif #endif
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include "caps.h" #include "caps.h"
#include "cgroup.h" #include "cgroup.h"
#include "config.h" #include "config.h"
#include "apparmor.h"
lxc_log_define(lxc_attach, lxc); lxc_log_define(lxc_attach, lxc);
...@@ -137,6 +138,7 @@ struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid) ...@@ -137,6 +138,7 @@ struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
errno = ENOENT; errno = ENOENT;
goto out_error; goto out_error;
} }
info->aa_profile = aa_get_profile(pid);
return info; return info;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <sys/types.h> #include <sys/types.h>
struct lxc_proc_context_info { struct lxc_proc_context_info {
char *aa_profile;
unsigned long personality; unsigned long personality;
unsigned long long capability_mask; unsigned long long capability_mask;
}; };
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "sync.h" #include "sync.h"
#include "log.h" #include "log.h"
#include "namespace.h" #include "namespace.h"
#include "apparmor.h"
#if HAVE_SYS_PERSONALITY_H #if HAVE_SYS_PERSONALITY_H
#include <sys/personality.h> #include <sys/personality.h>
...@@ -265,6 +266,11 @@ int main(int argc, char *argv[]) ...@@ -265,6 +266,11 @@ int main(int argc, char *argv[])
lxc_sync_fini_parent(handler); lxc_sync_fini_parent(handler);
lxc_cgroup_dispose_attach(cgroup_data); lxc_cgroup_dispose_attach(cgroup_data);
if (attach_apparmor(init_ctx->aa_profile) < 0) {
ERROR("failed switching apparmor profiles");
return -1;
}
/* A description of the purpose of this functionality is /* A description of the purpose of this functionality is
* provided in the lxc-attach(1) manual page. We have to * provided in the lxc-attach(1) manual page. We have to
* remount here and not in the parent process, otherwise * remount here and not in the parent process, otherwise
......
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