AM_CONDITIONAL([ENABLE_RPATH], [test "x$enable_rpath" = "xyes"])
+AC_ARG_ENABLE([apparmor],
+ [AC_HELP_STRING([--enable-apparmor], [enable apparmor])],
+ [], [enable_apparmor=yes])
+AM_CONDITIONAL([ENABLE_APPARMOR], [test "x$enable_apparmor" = "xyes"])
+
AC_ARG_ENABLE([doc],
[AC_HELP_STRING([--enable-doc], [make mans (require docbook2man installed) [default=auto]])],
[], [enable_doc=auto])
AC_MSG_ERROR([docbook2man required by man request, but not found])
fi
+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])])
+
AM_CONDITIONAL([ENABLE_DOCBOOK], [test "x$have_docbook" = "xyes"])
AC_ARG_ENABLE([examples],
mainloop.c mainloop.h \
af_unix.c af_unix.h \
\
- utmp.c utmp.h
+ utmp.c utmp.h \
+ apparmor.c apparmor.h
AM_CFLAGS=-I$(top_srcdir)/src \
-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
-DLXCPATH=\"$(LXCPATH)\" \
-DLXCINITDIR=\"$(LXCINITDIR)\"
+if ENABLE_APPARMOR
+AM_CFLAGS += -DHAVE_APPARMOR
+endif
+
liblxc_so_CFLAGS = -fPIC -DPIC $(AM_CFLAGS)
liblxc_so_LDFLAGS = \
-shared \
-Wl,-soname,liblxc.so.$(firstword $(subst ., ,$(VERSION)))
-liblxc_so_LDADD = -lutil $(CAP_LIBS)
+liblxc_so_LDADD = -lutil $(CAP_LIBS) $(APPARMOR_LIBS)
bin_SCRIPTS = \
lxc-ps \
if ENABLE_RPATH
AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir)
endif
-LDADD=liblxc.so @CAP_LIBS@
+LDADD=liblxc.so @CAP_LIBS@ @APPARMOR_LIBS@
lxc_attach_SOURCES = lxc_attach.c
lxc_cgroup_SOURCES = lxc_cgroup.c
--- /dev/null
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+
+#include "log.h"
+
+lxc_log_define(lxc_apparmor, lxc);
+
+#if HAVE_APPARMOR
+#include "apparmor.h"
+#include <sys/apparmor.h>
+
+#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)
+{
+ 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);
+ fclose(f);
+ if (ret < 1)
+ return 0;
+ if (strcmp(p, "unconfined") == 0)
+ return 1;
+ return 0;
+}
+
+/* aa_getcon is not working right now. Use our hand-rolled version below */
+static int check_apparmor_enabled(void)
+{
+ struct stat statbuf;
+ FILE *fin;
+ char e;
+ int ret;
+
+ ret = stat(AA_MOUNT_RESTR, &statbuf);
+ if (ret != 0)
+ return 0;
+ fin = fopen(AA_ENABLED_FILE, "r");
+ if (!fin)
+ return 0;
+ ret = fscanf(fin, "%c", &e);
+ fclose(fin);
+ if (ret == 1 && e == 'Y')
+ return 1;
+ return 0;
+}
+
+extern void apparmor_handler_init(struct lxc_handler *handler)
+{
+ handler->aa_enabled = check_apparmor_enabled();
+ INFO("aa_enabled set to %d\n", handler->aa_enabled);
+}
+
+#define AA_DEF_PROFILE "lxc-container-default"
+extern int apparmor_load(struct lxc_handler *handler)
+{
+ if (!handler->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 (strcmp(handler->conf->aa_profile, "unconfined") == 0 &&
+ 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);
+ return -1;
+ }
+ if (handler->conf->lsm_umount_proc == 1)
+ umount("/proc");
+
+ INFO("changed apparmor profile to %s", handler->conf->aa_profile);
+
+ return 0;
+}
+
+/*
+ * 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
+ */
+extern int lsm_mount_proc_if_needed(char *root_src, char *rootfs_tgt)
+{
+ char path[MAXPATHLEN];
+ char link[20];
+ int linklen, ret;
+
+ ret = snprintf(path, MAXPATHLEN, "%s/proc/self", root_src ? rootfs_tgt : "");
+ if (ret < 0 || ret >= MAXPATHLEN) {
+ SYSERROR("proc path name too long");
+ return -1;
+ }
+ memset(link, 0, 20);
+ linklen = readlink(path, link, 20);
+ INFO("I am %d, /proc/self points to %s\n", getpid(), link);
+ ret = snprintf(path, MAXPATHLEN, "%s/proc", root_src ? rootfs_tgt : "");
+ if (linklen < 0) /* /proc not mounted */
+ goto domount;
+ /* can't be longer than rootfs/proc/1 */
+ if (strncmp(link, "1", linklen) != 0) {
+ /* wrong /procs mounted */
+ umount2(path, MNT_DETACH); /* ignore failure */
+ goto domount;
+ }
+ /* the right proc is already mounted */
+ return 0;
+
+domount:
+ if (mount("proc", path, "proc", 0, NULL))
+ return -1;
+ INFO("Mounted /proc for the container\n");
+ return 1;
+}
+#else
+extern void apparmor_handler_init(struct lxc_handler *handler) {
+ INFO("apparmor_load - apparmor is disabled");
+}
+#endif
--- /dev/null
+#include <lxc/start.h> /* for lxc_handler */
+#include <lxc/conf.h>
+
+struct lxc_handler;
+
+#if HAVE_APPARMOR
+extern int apparmor_load(struct lxc_handler *handler);
+extern int lsm_mount_proc_if_needed(char *root_src, char *rootfs_tgt);
+extern void apparmor_handler_init(struct lxc_handler *handler);
+#else
+extern int apparmor_load(struct lxc_handler *handler);
+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
lxc_list_init(&new->network);
lxc_list_init(&new->mount_list);
lxc_list_init(&new->caps);
+#if HAVE_APPARMOR
+ new->aa_profile = NULL;
+#endif
+#if HAVE_APPARMOR /* || HAVE_SMACK || HAVE_SELINUX */
+ new->lsm_umount_proc = 0;
+#endif
return new;
}
int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
{
+#if HAVE_APPARMOR /* || HAVE_SMACK || HAVE_SELINUX */
+ int mounted;
+#endif
+
if (setup_utsname(lxc_conf->utsname)) {
ERROR("failed to setup the utsname for '%s'", name);
return -1;
return -1;
}
+#if HAVE_APPARMOR /* || HAVE_SMACK || HAVE_SELINUX */
+ mounted = lsm_mount_proc_if_needed(lxc_conf->rootfs.path, lxc_conf->rootfs.mount);
+ if (mounted == -1) {
+ SYSERROR("failed to mount /proc in the container.");
+ return -1;
+ } else if (mounted == 1) {
+ lxc_conf->lsm_umount_proc = 1;
+ }
+#endif
+
if (setup_pivot_root(&lxc_conf->rootfs)) {
ERROR("failed to set rootfs for '%s'", name);
return -1;
* @tty_info : tty data
* @console : console data
* @ttydir : directory (under /dev) in which to create console and ttys
+#if HAVE_APPARMOR
+ * @aa_profile : apparmor profile to switch to
+#endif
*/
struct lxc_conf {
char *fstab;
struct lxc_rootfs rootfs;
char *ttydir;
int close_all_fds;
+#if HAVE_APPARMOR
+ char *aa_profile;
+#endif
+#if HAVE_APPARMOR /* || HAVE_SELINUX || HAVE_SMACK */
+ int lsm_umount_proc;
+#endif
};
/*
static int config_pts(const char *, char *, struct lxc_conf *);
static int config_tty(const char *, char *, struct lxc_conf *);
static int config_ttydir(const char *, char *, struct lxc_conf *);
+#if HAVE_APPARMOR
+static int config_aa_profile(const char *, char *, struct lxc_conf *);
+#endif
static int config_cgroup(const char *, char *, struct lxc_conf *);
static int config_mount(const char *, char *, struct lxc_conf *);
static int config_rootfs(const char *, char *, struct lxc_conf *);
{ "lxc.pts", config_pts },
{ "lxc.tty", config_tty },
{ "lxc.devttydir", config_ttydir },
+#if HAVE_APPARMOR
+ { "lxc.aa_profile", config_aa_profile },
+#endif
{ "lxc.cgroup", config_cgroup },
{ "lxc.mount", config_mount },
{ "lxc.rootfs.mount", config_rootfs_mount },
return 0;
}
+#if HAVE_APPARMOR
+static int config_aa_profile(const char *key, char *value, struct lxc_conf *lxc_conf)
+{
+ char *path;
+
+ if (!value || strlen(value) == 0)
+ return 0;
+ path = strdup(value);
+ if (!path) {
+ SYSERROR("failed to strdup '%s': %m", value);
+ return -1;
+ }
+
+ lxc_conf->aa_profile = path;
+
+ return 0;
+}
+#endif
+
static int config_cgroup(const char *key, char *value, struct lxc_conf *lxc_conf)
{
char *token = "lxc.cgroup.";
#include "console.h"
#include "sync.h"
#include "namespace.h"
+#include "apparmor.h"
lxc_log_define(lxc_start, lxc);
handler->conf = conf;
+ apparmor_handler_init(handler);
handler->name = strdup(name);
if (!handler->name) {
ERROR("failed to allocate memory");
goto out_warn_father;
}
+ if (apparmor_load(handler) < 0)
+ goto out_warn_father;
+
close(handler->sigfd);
/* after this call, we are in error because this
struct lxc_operations *ops;
void *data;
int sv[2];
+#if HAVE_APPARMOR
+ int aa_enabled;
+#endif
};
extern struct lxc_handler *lxc_init(const char *name, struct lxc_conf *);