diff --git a/configure.ac b/configure.ac index 0bcd75a28..6713539b4 100644 --- a/configure.ac +++ b/configure.ac @@ -258,11 +258,6 @@ if test "$enable_apparmor" = "auto" ; then fi AM_CONDITIONAL([ENABLE_APPARMOR], [test "x$enable_apparmor" = "xyes"]) -AM_COND_IF([ENABLE_APPARMOR], - [AC_CHECK_HEADER([sys/apparmor.h],[],[AC_MSG_ERROR([You must install the AppArmor development package in order to compile lxc])]) - AC_CHECK_LIB([apparmor], [aa_change_profile],[],[AC_MSG_ERROR([You must install the AppArmor development package in order to compile lxc])]) - AC_SUBST([APPARMOR_LIBS], [-lapparmor])]) - # GnuTLS AC_ARG_ENABLE([gnutls], [AC_HELP_STRING([--enable-gnutls], [enable GnuTLS support [default=auto]])], diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index 895684e0b..8f9a7ab29 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -207,7 +207,7 @@ liblxc_la_LDFLAGS = \ -Wl,-soname,liblxc.so.$(firstword $(subst ., ,@LXC_ABI@)) \ -version-info @LXC_ABI_MAJOR@ -liblxc_la_LIBADD = $(CAP_LIBS) $(APPARMOR_LIBS) $(SELINUX_LIBS) $(SECCOMP_LIBS) +liblxc_la_LIBADD = $(CAP_LIBS) $(SELINUX_LIBS) $(SECCOMP_LIBS) if ENABLE_CGMANAGER liblxc_la_LIBADD += $(CGMANAGER_LIBS) $(DBUS_LIBS) $(NIH_LIBS) $(NIH_DBUS_LIBS) @@ -264,7 +264,7 @@ AM_LDFLAGS = -Wl,-E if ENABLE_RPATH AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir) endif -LDADD=liblxc.la @CAP_LIBS@ @APPARMOR_LIBS@ @SELINUX_LIBS@ @SECCOMP_LIBS@ +LDADD=liblxc.la @CAP_LIBS@ @SELINUX_LIBS@ @SECCOMP_LIBS@ lxc_attach_SOURCES = tools/lxc_attach.c tools/arguments.c lxc_autostart_SOURCES = tools/lxc_autostart.c tools/arguments.c diff --git a/src/lxc/attach.c b/src/lxc/attach.c index 8444eaf12..6d3377f3e 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -88,104 +88,6 @@ lxc_log_define(lxc_attach, lxc); -/* /proc/pid-to-str/current\0 = (5 + 21 + 7 + 1) */ -#define __LSMATTRLEN (5 + (LXC_NUMSTRLEN64) + 7 + 1) -static int lsm_open(pid_t pid, int on_exec) -{ - const char *name; - char path[__LSMATTRLEN]; - int ret = -1; - int labelfd = -1; - - name = lsm_name(); - - if (strcmp(name, "nop") == 0) - return 0; - - if (strcmp(name, "none") == 0) - return 0; - - /* We don't support on-exec with AppArmor */ - if (strcmp(name, "AppArmor") == 0) - on_exec = 0; - - if (on_exec) - ret = snprintf(path, __LSMATTRLEN, "/proc/%d/attr/exec", pid); - else - ret = snprintf(path, __LSMATTRLEN, "/proc/%d/attr/current", pid); - if (ret < 0 || ret >= __LSMATTRLEN) - return -1; - - labelfd = open(path, O_RDWR); - if (labelfd < 0) { - SYSERROR("%s - Unable to open file descriptor to set LSM label", - strerror(errno)); - return -1; - } - - return labelfd; -} - -static int lsm_set_label_at(int lsm_labelfd, int on_exec, char *lsm_label) -{ - int fret = -1; - const char *name; - char *command = NULL; - - name = lsm_name(); - - if (strcmp(name, "nop") == 0) - return 0; - - if (strcmp(name, "none") == 0) - return 0; - - /* We don't support on-exec with AppArmor */ - if (strcmp(name, "AppArmor") == 0) - on_exec = 0; - - if (strcmp(name, "AppArmor") == 0) { - int size; - - command = - malloc(strlen(lsm_label) + strlen("changeprofile ") + 1); - if (!command) { - SYSERROR("Failed to write apparmor profile."); - goto out; - } - - size = sprintf(command, "changeprofile %s", lsm_label); - if (size < 0) { - SYSERROR("Failed to write apparmor profile."); - goto out; - } - - if (write(lsm_labelfd, command, size + 1) < 0) { - SYSERROR("Unable to set LSM label: %s.", command); - goto out; - } - INFO("Set LSM label to: %s.", command); - } else if (strcmp(name, "SELinux") == 0) { - if (write(lsm_labelfd, lsm_label, strlen(lsm_label) + 1) < 0) { - SYSERROR("Unable to set LSM label: %s.", lsm_label); - goto out; - } - INFO("Set LSM label to: %s.", lsm_label); - } else { - ERROR("Unable to restore label for unknown LSM: %s.", name); - goto out; - } - fret = 0; - -out: - free(command); - - if (lsm_labelfd != -1) - close(lsm_labelfd); - - return fret; -} - /* /proc/pid-to-str/status\0 = (5 + 21 + 7 + 1) */ #define __PROC_STATUS_LEN (5 + (LXC_NUMSTRLEN64) + 7 + 1) static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid) @@ -962,15 +864,15 @@ static int attach_child_main(struct attach_clone_payload *payload) } if (needs_lsm) { - int on_exec; + bool on_exec; /* Change into our new LSM profile. */ - on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0; - ret = lsm_set_label_at(lsm_fd, on_exec, init_ctx->lsm_label); + on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? true : false; + ret = lsm_process_label_set_at(lsm_fd, init_ctx->lsm_label, on_exec); close(lsm_fd); if (ret < 0) goto on_error; - TRACE("Set LSM label"); + TRACE("Set %s LSM label to \"%s\"", lsm_name(), init_ctx->lsm_label); } if (init_ctx->container && init_ctx->container->lxc_conf && @@ -1409,11 +1311,12 @@ int lxc_attach(const char *name, const char *lxcpath, if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label) { - int labelfd, on_exec; int ret = -1; + int labelfd; + bool on_exec; - on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0; - labelfd = lsm_open(attached_pid, on_exec); + on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? true : false; + labelfd = lsm_process_label_fd_get(attached_pid, on_exec); if (labelfd < 0) goto close_mainloop; TRACE("Opened LSM label file descriptor %d", labelfd); diff --git a/src/lxc/lsm/apparmor.c b/src/lxc/lsm/apparmor.c index 2faa9a20d..85b70de8d 100644 --- a/src/lxc/lsm/apparmor.c +++ b/src/lxc/lsm/apparmor.c @@ -25,11 +25,10 @@ #include #include #include -#include #include #include "log.h" -#include "lsm/lsm.h" +#include "lsm.h" #include "conf.h" #include "utils.h" @@ -172,8 +171,10 @@ static bool aa_needs_transition(char *curlabel) * Notes: This relies on /proc being available. */ static int apparmor_process_label_set(const char *inlabel, struct lxc_conf *conf, - int use_default, int on_exec) + bool use_default, bool on_exec) { + int label_fd, ret; + pid_t tid; const char *label = inlabel ? inlabel : conf->lsm_aa_profile; char *curlabel; @@ -230,12 +231,21 @@ static int apparmor_process_label_set(const char *inlabel, struct lxc_conf *conf return 0; } - if (aa_change_profile(label) < 0) { - SYSERROR("failed to change apparmor profile to %s", label); + tid = lxc_raw_gettid(); + label_fd = lsm_process_label_fd_get(tid, on_exec); + if (label_fd < 0) { + SYSERROR("Failed to change apparmor profile to %s", label); return -1; } - INFO("changed apparmor profile to %s", label); + ret = lsm_process_label_set_at(label_fd, label, on_exec); + close(label_fd); + if (ret < 0) { + SYSERROR("Failed to change apparmor profile to %s", label); + return -1; + } + + INFO("Changed apparmor profile to %s", label); return 0; } diff --git a/src/lxc/lsm/lsm.c b/src/lxc/lsm/lsm.c index 79f837fc6..677f53a61 100644 --- a/src/lxc/lsm/lsm.c +++ b/src/lxc/lsm/lsm.c @@ -85,8 +85,97 @@ char *lsm_process_label_get(pid_t pid) return drv->process_label_get(pid); } +int lsm_process_label_fd_get(pid_t pid, bool on_exec) +{ + int ret = -1; + int labelfd = -1; + const char *name; + char path[LXC_LSMATTRLEN]; + + name = lsm_name(); + + if (strcmp(name, "nop") == 0) + return 0; + + if (strcmp(name, "none") == 0) + return 0; + + /* We don't support on-exec with AppArmor */ + if (strcmp(name, "AppArmor") == 0) + on_exec = 0; + + if (on_exec) + ret = snprintf(path, LXC_LSMATTRLEN, "/proc/%d/attr/exec", pid); + else + ret = snprintf(path, LXC_LSMATTRLEN, "/proc/%d/attr/current", pid); + if (ret < 0 || ret >= LXC_LSMATTRLEN) + return -1; + + labelfd = open(path, O_RDWR); + if (labelfd < 0) { + SYSERROR("%s - Unable to %s LSM label file descriptor", + name, strerror(errno)); + return -1; + } + + return labelfd; +} + +int lsm_process_label_set_at(int label_fd, const char *label, bool on_exec) +{ + int ret = -1; + const char *name; + + name = lsm_name(); + + if (strcmp(name, "nop") == 0) + return 0; + + if (strcmp(name, "none") == 0) + return 0; + + /* We don't support on-exec with AppArmor */ + if (strcmp(name, "AppArmor") == 0) + on_exec = false; + + if (strcmp(name, "AppArmor") == 0) { + size_t len; + char *command; + + if (on_exec) { + ERROR("Changing AppArmor profile on exec not supported"); + return -EINVAL; + } + + len = strlen(label) + strlen("changeprofile ") + 1; + command = malloc(len); + if (!command) + return -1; + + ret = snprintf(command, len, "changeprofile %s", label); + if (ret < 0 || (size_t)ret >= len) { + free(command); + return -1; + } + + ret = lxc_write_nointr(label_fd, command, len - 1); + free(command); + } else if (strcmp(name, "SELinux") == 0) { + ret = lxc_write_nointr(label_fd, label, strlen(label)); + } else { + ret = -EINVAL; + } + if (ret < 0) { + SYSERROR("Failed to set %s label \"%s\"", name, label); + return -1; + } + + INFO("Set %s label to \"%s\"", name, label); + return 0; +} + int lsm_process_label_set(const char *label, struct lxc_conf *conf, - int use_default, int on_exec) + bool use_default, bool on_exec) { if (!drv) { ERROR("LSM driver not inited"); diff --git a/src/lxc/lsm/lsm.h b/src/lxc/lsm/lsm.h index b915e8ddd..33a412b7b 100644 --- a/src/lxc/lsm/lsm.h +++ b/src/lxc/lsm/lsm.h @@ -28,29 +28,66 @@ struct lxc_conf; #include +#include "../utils.h" + +#define LXC_LSMATTRLEN (5 + (LXC_NUMSTRLEN64) + 7 + 1) + struct lsm_drv { const char *name; - int (*enabled)(void); + int (*enabled)(void); char *(*process_label_get)(pid_t pid); - int (*process_label_set)(const char *label, struct lxc_conf *conf, - int use_default, int on_exec); + int (*process_label_set)(const char *label, struct lxc_conf *conf, + bool use_default, bool on_exec); }; #if HAVE_APPARMOR || HAVE_SELINUX -void lsm_init(void); -int lsm_enabled(void); -const char *lsm_name(void); -char *lsm_process_label_get(pid_t pid); -int lsm_process_label_set(const char *label, struct lxc_conf *conf, - int use_default, int on_exec); +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_label_set(const char *label, struct lxc_conf *conf, + bool use_default, 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); #else -static inline void lsm_init(void) { } -static inline int lsm_enabled(void) { return 0; } -static inline const char *lsm_name(void) { return "none"; } -static inline char *lsm_process_label_get(pid_t pid) { return NULL; } -static inline int lsm_process_label_set(const char *label, - struct lxc_conf *conf, int use_default, int on_exec) { return 0; } +static inline void lsm_init(void) +{ + return; +} + +static inline int lsm_enabled(void) { + return 0; +} + +static inline const char *lsm_name(void) +{ + return "none"; +} + +static inline char *lsm_process_label_get(pid_t pid) +{ + return NULL; +} + +static inline int lsm_process_label_set(const char *label, + struct lxc_conf *conf, bool use_default, + bool on_exec) +{ + return 0; +} + +static inline int lsm_process_label_fd_get(pid_t pid, bool on_exec) +{ + return 0; +} + +extern int lsm_process_label_set_at(int label_fd, const char *label, + bool on_exec) +{ + return 0; +} #endif #endif diff --git a/src/lxc/lsm/nop.c b/src/lxc/lsm/nop.c index c13d8f528..7bb8121b8 100644 --- a/src/lxc/lsm/nop.c +++ b/src/lxc/lsm/nop.c @@ -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, - int use_default, int on_exec) + bool use_default, bool on_exec) { return 0; } diff --git a/src/lxc/lsm/selinux.c b/src/lxc/lsm/selinux.c index 46554d84c..857fe29a8 100644 --- a/src/lxc/lsm/selinux.c +++ b/src/lxc/lsm/selinux.c @@ -72,7 +72,7 @@ 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, - int use_default, int on_exec) + bool use_default, bool on_exec) { const char *label = inlabel ? inlabel : conf->lsm_se_context; if (!label) { diff --git a/src/lxc/utils.h b/src/lxc/utils.h index 92e13c507..223580edc 100644 --- a/src/lxc/utils.h +++ b/src/lxc/utils.h @@ -565,4 +565,13 @@ static inline uint64_t lxc_getpagesize(void) */ extern uint64_t lxc_find_next_power2(uint64_t n); +static inline pid_t lxc_raw_gettid(void) +{ +#ifdef SYS_gettid + return syscall(SYS_gettid); +#else + return lxc_raw_getpid(); +#endif +} + #endif /* __LXC_UTILS_H */