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: Serge Hallyn <serge.hal...@ubuntu.com> --- src/lxc/apparmor.c | 105 ++++++++++++++++++++++++++++++++++++++++----------- src/lxc/apparmor.h | 22 ++++++++++- src/lxc/attach.c | 2 + src/lxc/attach.h | 1 + src/lxc/lxc_attach.c | 6 +++ 5 files changed, 111 insertions(+), 25 deletions(-) diff --git a/src/lxc/apparmor.c b/src/lxc/apparmor.c index ae3d8f7..c2d1d2f 100644 --- a/src/lxc/apparmor.c +++ b/src/lxc/apparmor.c @@ -1,4 +1,5 @@ #include <stdio.h> +#include <stdlib.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> @@ -16,21 +17,58 @@ lxc_log_define(lxc_apparmor, lxc); #define AA_MOUNT_RESTR "/sys/kernel/security/apparmor/features/mount/mask" #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; - char path[100], p[100]; - sprintf(path, "/proc/%d/attr/current", getpid()); - FILE *f = fopen(path, "r"); - if (!f) - return 0; - ret = fscanf(f, "%99s", p); + char *buf = NULL; + int sz = 0; + FILE *f; + + ret = snprintf(path, 100, "/proc/%d/attr/current", pid); + 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); - if (ret < 1) - return 0; - if (strcmp(p, "unconfined") == 0) - return 1; - return 0; + if (ret >= sz) + goto again; + if (ret < 0) { + ERROR("reading %s\n", path); + 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 */ @@ -61,36 +99,57 @@ extern void apparmor_handler_init(struct lxc_handler *handler) } #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"); return 0; } INFO("setting up apparmor"); - if (!handler->conf->aa_profile) - handler->conf->aa_profile = AA_DEF_PROFILE; + if (!aa_profile) + aa_profile = AA_DEF_PROFILE; - if (strcmp(handler->conf->aa_profile, "unconfined") == 0 && - aa_am_unconfined()) { + if (strcmp(aa_profile, "unconfined") == 0 && !dropprivs && aa_am_unconfined()) { INFO("apparmor profile unchanged"); return 0; } - //if (aa_change_onexec(handler->conf->aa_profile) < 0) { - if (aa_change_profile(handler->conf->aa_profile) < 0) { - SYSERROR("failed to change apparmor profile to %s", handler->conf->aa_profile); + //if (aa_change_onexec(aa_profile) < 0) { + if (aa_change_profile(aa_profile) < 0) { + SYSERROR("failed to change apparmor profile to %s", aa_profile); return -1; } - if (handler->conf->lsm_umount_proc == 1) + if (umount_proc == 1) umount("/proc"); - INFO("changed apparmor profile to %s", handler->conf->aa_profile); + INFO("changed apparmor profile to %s", aa_profile); 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 * also want proc mounted in the container so as to transition diff --git a/src/lxc/apparmor.h b/src/lxc/apparmor.h index af879c0..d714478 100644 --- a/src/lxc/apparmor.h +++ b/src/lxc/apparmor.h @@ -3,16 +3,34 @@ 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 +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 attach_apparmor(char *profile); extern int lsm_mount_proc_if_needed(char *root_src, char *rootfs_tgt); -extern void apparmor_handler_init(struct lxc_handler *handler); #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) { return 0; } static inline int lsm_mount_proc_if_needed(char *root_src, char *rootfs_tgt) { return 0; } -extern void apparmor_handler_init(struct lxc_handler *handler); #endif diff --git a/src/lxc/attach.c b/src/lxc/attach.c index b86d2f4..af3d7a0 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -44,6 +44,7 @@ #include "caps.h" #include "cgroup.h" #include "config.h" +#include "apparmor.h" lxc_log_define(lxc_attach, lxc); @@ -137,6 +138,7 @@ struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid) errno = ENOENT; goto out_error; } + info->aa_profile = aa_get_profile(pid); return info; diff --git a/src/lxc/attach.h b/src/lxc/attach.h index aab47e3..4d4f719 100644 --- a/src/lxc/attach.h +++ b/src/lxc/attach.h @@ -27,6 +27,7 @@ #include <sys/types.h> struct lxc_proc_context_info { + char *aa_profile; unsigned long personality; unsigned long long capability_mask; }; diff --git a/src/lxc/lxc_attach.c b/src/lxc/lxc_attach.c index 370bfbc..e1511ef 100644 --- a/src/lxc/lxc_attach.c +++ b/src/lxc/lxc_attach.c @@ -41,6 +41,7 @@ #include "sync.h" #include "log.h" #include "namespace.h" +#include "apparmor.h" #if HAVE_SYS_PERSONALITY_H #include <sys/personality.h> @@ -265,6 +266,11 @@ int main(int argc, char *argv[]) lxc_sync_fini_parent(handler); 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 * provided in the lxc-attach(1) manual page. We have to * remount here and not in the parent process, otherwise -- 1.8.1.2 ------------------------------------------------------------------------------ Everyone hates slow websites. So do we. Make your web apps faster with AppDynamics Download AppDynamics Lite for free today: http://p.sf.net/sfu/appdyn_d2d_feb _______________________________________________ Lxc-devel mailing list Lxc-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/lxc-devel