Quoting Dwight Engen (dwight.en...@oracle.com): > Currently, a maximum of one LSM within LXC will be initialized and > used. If in the future stacked LSMs become a reality, we can support it > without changing the configuration syntax and add support for more than > a single LSM at a time to the lsm code. > > Generic LXC code should note that lsm_process_label_set() will take > effect "now" for AppArmor, and upon exec() for SELinux. > > - fix Oracle template mounting of proc and sysfs, needed when using SELinux > > Signed-off-by: Dwight Engen <dwight.en...@oracle.com>
Thanks, Dwight, this worked perfectly for me with and without apparmor compiled in. Tested lxc-start and lxc-attach (and checked new context of course) Acked-by: Serge E. Hallyn <serge.hal...@ubuntu.com> > --- > configure.ac | 14 +++ > doc/lxc.conf.sgml.in | 25 ++++++ > src/lxc/Makefile.am | 21 ++++- > src/lxc/apparmor.c | 230 > ------------------------------------------------ > src/lxc/apparmor.h | 56 ------------ > src/lxc/attach.c | 31 +++---- > src/lxc/attach.h | 2 +- > src/lxc/conf.c | 43 +++------ > src/lxc/conf.h | 12 +-- > src/lxc/confile.c | 56 +++++++----- > src/lxc/lsm/apparmor.c | 179 +++++++++++++++++++++++++++++++++++++ > src/lxc/lsm/lsm.c | 156 ++++++++++++++++++++++++++++++++ > src/lxc/lsm/lsm.h | 52 +++++++++++ > src/lxc/lsm/nop.c | 46 ++++++++++ > src/lxc/lsm/selinux.c | 101 +++++++++++++++++++++ > src/lxc/start.c | 15 +++- > src/lxc/start.h | 3 - > templates/lxc-oracle.in | 9 +- > 18 files changed, 674 insertions(+), 377 deletions(-) > delete mode 100644 src/lxc/apparmor.c > delete mode 100644 src/lxc/apparmor.h > create mode 100644 src/lxc/lsm/apparmor.c > create mode 100644 src/lxc/lsm/lsm.c > create mode 100644 src/lxc/lsm/lsm.h > create mode 100644 src/lxc/lsm/nop.c > create mode 100644 src/lxc/lsm/selinux.c > > diff --git a/configure.ac b/configure.ac > index adc4e8a..1a5c8aa 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -116,6 +116,20 @@ AM_COND_IF([ENABLE_APPARMOR], > 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])]) > > +# SELinux > +AC_ARG_ENABLE([selinux], > + [AC_HELP_STRING([--enable-selinux], [enable SELinux support])], > + [], [enable_selinux=check]) > + > +if test "x$enable_selinux" = xcheck; then > + > AC_CHECK_LIB([selinux],[setexeccon_raw],[enable_selinux=yes],[enable_selinux=no]) > +fi > +AM_CONDITIONAL([ENABLE_SELINUX], [test "x$enable_selinux" = "xyes"]) > +AM_COND_IF([ENABLE_SELINUX], > + [AC_CHECK_HEADER([selinux/selinux.h],[],[AC_MSG_ERROR([You must install > the SELinux development package in order to compile lxc])]) > + AC_CHECK_LIB([selinux], [setexeccon_raw],[],[AC_MSG_ERROR([You must > install the SELinux development package in order to compile lxc])]) > + AC_SUBST([SELINUX_LIBS])]) > + > # Seccomp syscall filter > AC_ARG_ENABLE([seccomp], > [AC_HELP_STRING([--enable-seccomp], [enable seccomp])], > diff --git a/doc/lxc.conf.sgml.in b/doc/lxc.conf.sgml.in > index dc416e8..bad553c 100644 > --- a/doc/lxc.conf.sgml.in > +++ b/doc/lxc.conf.sgml.in > @@ -811,6 +811,31 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, > Boston, MA 02110-1301 USA > </refsect2> > > <refsect2> > + <title>SELinux context</title> > + <para> > + If lxc was compiled and installed with SELinux support, and the host > + system has SELinux enabled, then the SELinux context under which the > + container should be run can be specified in the container > + configuration. The default is <command>unconfined_t</command>, > + which means that lxc will not attempt to change contexts. > + </para> > + <variablelist> > + <varlistentry> > + <term> > + <option>lxc.se_context</option> > + </term> > + <listitem> > + <para> > + Specify the SELinux context under which the container should > + be run or <command>unconfined_t</command>. For example > + </para> > + <programlisting>lxc.se_context = > unconfined_u:unconfined_r:lxc_t:s0-s0:c0.c1023</programlisting> > + </listitem> > + </varlistentry> > + </variablelist> > + </refsect2> > + > + <refsect2> > <title>Seccomp configuration</title> > <para> > A container can be started with a reduced set of available > diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am > index f19a994..873b97d 100644 > --- a/src/lxc/Makefile.am > +++ b/src/lxc/Makefile.am > @@ -37,6 +37,18 @@ sodir=$(libdir) > # use PROGRAMS to avoid complains from automake > so_PROGRAMS = liblxc.so > > +LSM_SOURCES = \ > + lsm/nop.c \ > + lsm/lsm.h lsm/lsm.c > + > +if ENABLE_APPARMOR > +LSM_SOURCES += lsm/apparmor.c > +endif > + > +if ENABLE_SELINUX > +LSM_SOURCES += lsm/selinux.c > +endif > + > liblxc_so_SOURCES = \ > arguments.c arguments.h \ > bdev.c bdev.h \ > @@ -73,10 +85,11 @@ liblxc_so_SOURCES = \ > af_unix.c af_unix.h \ > \ > lxcutmp.c lxcutmp.h \ > - apparmor.c apparmor.h \ > lxclock.h lxclock.c \ > lxccontainer.c lxccontainer.h \ > - version.c version.h > + version.c version.h \ > + \ > + $(LSM_SOURCES) > > if IS_BIONIC > liblxc_so_SOURCES += \ > @@ -107,6 +120,10 @@ if ENABLE_APPARMOR > AM_CFLAGS += -DHAVE_APPARMOR > endif > > +if ENABLE_SELINUX > +AM_CFLAGS += -DHAVE_SELINUX > +endif > + > if HAVE_NEWUIDMAP > AM_CFLAGS += -DHAVE_NEWUIDMAP > endif > diff --git a/src/lxc/apparmor.c b/src/lxc/apparmor.c > deleted file mode 100644 > index c31cce7..0000000 > --- a/src/lxc/apparmor.c > +++ /dev/null > @@ -1,230 +0,0 @@ > -/* apparmor > - * > - * Copyright © 2012 Serge Hallyn <serge.hal...@ubuntu.com>. > - * Copyright © 2012 Canonical Ltd. > - * > - * 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 > - */ > - > -#include <stdio.h> > -#include <stdlib.h> > -#include <unistd.h> > -#include <errno.h> > -#include <sys/types.h> > -#include <sys/stat.h> > -#include <sys/mount.h> > - > -#include "log.h" > -#include "apparmor.h" > -#include "lxclock.h" > - > -lxc_log_define(lxc_apparmor, lxc); > - > -#if HAVE_APPARMOR > -#include <sys/apparmor.h> > - > -#define AA_MOUNT_RESTR "/sys/kernel/security/apparmor/features/mount/mask" > -#define AA_ENABLED_FILE "/sys/module/apparmor/parameters/enabled" > - > - > -/* caller must free the returned profile */ > -extern char *aa_get_profile(pid_t pid) > -{ > - char path[100], *space; > - int ret; > - 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: > - process_lock(); > - f = fopen(path, "r"); > - process_unlock(); > - if (!f) { > - SYSERROR("opening %s\n", path); > - if (buf) > - free(buf); > - return NULL; > - } > - sz += 1024; > - buf = realloc(buf, sz); > - memset(buf, 0, sz); > - if (!buf) { > - ERROR("out of memory"); > - process_lock(); > - fclose(f); > - process_unlock(); > - return NULL; > - } > - ret = fread(buf, 1, sz - 1, f); > - process_lock(); > - fclose(f); > - process_unlock(); > - if (ret >= sz) > - goto again; > - if (ret < 0) { > - ERROR("reading %s\n", path); > - free(buf); > - return NULL; > - } > - space = index(buf, '\n'); > - if (space) > - *space = '\0'; > - 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 */ > -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; > - process_lock(); > - fin = fopen(AA_ENABLED_FILE, "r"); > - process_unlock(); > - if (!fin) > - return 0; > - ret = fscanf(fin, "%c", &e); > - process_lock(); > - fclose(fin); > - process_unlock(); > - 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 do_apparmor_load(int aa_enabled, char *aa_profile, > - int umount_proc, int dropprivs) > -{ > - if (!aa_enabled) { > - INFO("apparmor not enabled"); > - return 0; > - } > - INFO("setting up apparmor"); > - > - if (!aa_profile) > - aa_profile = AA_DEF_PROFILE; > - > - if (strcmp(aa_profile, "unconfined") == 0 && !dropprivs && > aa_am_unconfined()) { > - INFO("apparmor profile unchanged"); > - return 0; > - } > - > - //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 (umount_proc == 1) > - umount("/proc"); > - > - 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 > - */ > -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 > diff --git a/src/lxc/apparmor.h b/src/lxc/apparmor.h > deleted file mode 100644 > index e27a728..0000000 > --- a/src/lxc/apparmor.h > +++ /dev/null > @@ -1,56 +0,0 @@ > -/* apparmor > - * > - * Copyright © 2012 Serge Hallyn <serge.hal...@ubuntu.com>. > - * Copyright © 2012 Canonical Ltd. > - * > - * 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 > - */ > - > -#include <lxc/start.h> /* for lxc_handler */ > -#include <lxc/conf.h> > - > -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); > -#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; > -} > -#endif > diff --git a/src/lxc/attach.c b/src/lxc/attach.c > index cc95079..37cefb0 100644 > --- a/src/lxc/attach.c > +++ b/src/lxc/attach.c > @@ -46,11 +46,11 @@ > #include "attach.h" > #include "caps.h" > #include "config.h" > -#include "apparmor.h" > #include "utils.h" > #include "commands.h" > #include "cgroup.h" > #include "lxclock.h" > +#include "lsm/lsm.h" > > #if HAVE_SYS_PERSONALITY_H > #include <sys/personality.h> > @@ -129,7 +129,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); > + info->lsm_label = lsm_process_label_get(pid); > > return info; > > @@ -138,6 +138,13 @@ out_error: > return NULL; > } > > +static void lxc_proc_put_context_info(struct lxc_proc_context_info *ctx) > +{ > + if (ctx->lsm_label) > + free(ctx->lsm_label); > + free(ctx); > +} > + > int lxc_attach_to_ns(pid_t pid, int which) > { > char path[MAXPATHLEN]; > @@ -644,8 +651,7 @@ int lxc_attach(const char* name, const char* lxcpath, > lxc_attach_exec_t exec_fun > ERROR("failed to automatically determine the " > "namespaces which the container unshared"); > free(cwd); > - free(init_ctx->aa_profile); > - free(init_ctx); > + lxc_proc_put_context_info(init_ctx); > return -1; > } > } > @@ -683,8 +689,7 @@ int lxc_attach(const char* name, const char* lxcpath, > lxc_attach_exec_t exec_fun > if (ret < 0) { > SYSERROR("could not set up required IPC mechanism for > attaching"); > free(cwd); > - free(init_ctx->aa_profile); > - free(init_ctx); > + lxc_proc_put_context_info(init_ctx); > return -1; > } > > @@ -705,8 +710,7 @@ int lxc_attach(const char* name, const char* lxcpath, > lxc_attach_exec_t exec_fun > if (pid < 0) { > SYSERROR("failed to create first subprocess"); > free(cwd); > - free(init_ctx->aa_profile); > - free(init_ctx); > + lxc_proc_put_context_info(init_ctx); > return -1; > } > > @@ -794,8 +798,7 @@ int lxc_attach(const char* name, const char* lxcpath, > lxc_attach_exec_t exec_fun > process_lock(); > close(ipc_sockets[0]); > process_unlock(); > - free(init_ctx->aa_profile); > - free(init_ctx); > + lxc_proc_put_context_info(init_ctx); > > /* we're done, the child process should now execute whatever > * it is that the user requested. The parent can now track it > @@ -815,8 +818,7 @@ int lxc_attach(const char* name, const char* lxcpath, > lxc_attach_exec_t exec_fun > process_unlock(); > if (to_cleanup_pid) > (void) wait_for_pid(to_cleanup_pid); > - free(init_ctx->aa_profile); > - free(init_ctx); > + lxc_proc_put_context_info(init_ctx); > return -1; > } > > @@ -918,7 +920,7 @@ int attach_child_main(void* data) > > /* load apparmor profile */ > if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & > LXC_ATTACH_APPARMOR)) { > - ret = attach_apparmor(init_ctx->aa_profile); > + ret = lsm_process_label_set(init_ctx->lsm_label, 0); > if (ret < 0) { > shutdown(ipc_socket, SHUT_RDWR); > rexit(-1); > @@ -1021,8 +1023,7 @@ int attach_child_main(void* data) > > shutdown(ipc_socket, SHUT_RDWR); > close(ipc_socket); > - free(init_ctx->aa_profile); > - free(init_ctx); > + lxc_proc_put_context_info(init_ctx); > > /* The following is done after the communication socket is > * shut down. That way, all errors that might (though > diff --git a/src/lxc/attach.h b/src/lxc/attach.h > index 518d086..b5f3ea1 100644 > --- a/src/lxc/attach.h > +++ b/src/lxc/attach.h > @@ -28,7 +28,7 @@ > #include "attach_options.h" > > struct lxc_proc_context_info { > - char *aa_profile; > + char *lsm_label; > unsigned long personality; > unsigned long long capability_mask; > }; > diff --git a/src/lxc/conf.c b/src/lxc/conf.c > index e933c9a..18a92c9 100644 > --- a/src/lxc/conf.c > +++ b/src/lxc/conf.c > @@ -74,10 +74,7 @@ > #include "bdev.h" > #include "cgroup.h" > #include "lxclock.h" > - > -#if HAVE_APPARMOR > -#include <apparmor.h> > -#endif > +#include "lsm/lsm.h" > > #if HAVE_SYS_CAPABILITY_H > #include <sys/capability.h> > @@ -2398,12 +2395,9 @@ struct lxc_conf *lxc_conf_init(void) > lxc_list_init(&new->id_map); > for (i=0; i<NUM_LXC_HOOKS; i++) > lxc_list_init(&new->hooks[i]); > -#if HAVE_APPARMOR > - new->aa_profile = NULL; > -#endif > -#if HAVE_APPARMOR /* || HAVE_SMACK || HAVE_SELINUX */ > + new->lsm_aa_profile = NULL; > + new->lsm_se_context = NULL; > new->lsm_umount_proc = 0; > -#endif > > return new; > } > @@ -3043,10 +3037,6 @@ int uid_shift_ttys(int pid, struct lxc_conf *conf) > > int lxc_setup(const char *name, struct lxc_conf *lxc_conf, const char > *lxcpath, struct cgroup_process_info *cgroup_info) > { > -#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; > @@ -3140,24 +3130,11 @@ int lxc_setup(const char *name, struct lxc_conf > *lxc_conf, const char *lxcpath, > return -1; > } > > -#if HAVE_APPARMOR /* || HAVE_SMACK || HAVE_SELINUX */ > - INFO("rootfs path is .%s., mount is .%s.", lxc_conf->rootfs.path, > - lxc_conf->rootfs.mount); > - if (lxc_conf->rootfs.path == NULL || strlen(lxc_conf->rootfs.path) == > 0) { > - if (mount("proc", "/proc", "proc", 0, NULL)) { > - SYSERROR("Failed mounting /proc, proceeding"); > - mounted = 0; > - } else > - mounted = 1; > - } else > - 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."); > + /* mount /proc if needed for LSM transition */ > + if (lsm_proc_mount(lxc_conf) < 0) { > + ERROR("failed to LSM mount proc for '%s'", name); > 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); > @@ -3488,10 +3465,10 @@ void lxc_conf_free(struct lxc_conf *conf) > if (conf->rcfile) > free(conf->rcfile); > lxc_clear_config_network(conf); > -#if HAVE_APPARMOR > - if (conf->aa_profile) > - free(conf->aa_profile); > -#endif > + if (conf->lsm_aa_profile) > + free(conf->lsm_aa_profile); > + if (conf->lsm_se_context) > + free(conf->lsm_se_context); > lxc_seccomp_free(conf); > lxc_clear_config_caps(conf); > lxc_clear_config_keepcaps(conf); > diff --git a/src/lxc/conf.h b/src/lxc/conf.h > index d99bdfe..8c2dc4e 100644 > --- a/src/lxc/conf.h > +++ b/src/lxc/conf.h > @@ -247,9 +247,8 @@ enum { > * @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 > + * @lsm_aa_profile : apparmor profile to switch to or NULL > + * @lsm_se_context : selinux type to switch to or NULL > */ > enum lxchooks { > LXCHOOK_PRESTART, LXCHOOK_PREMOUNT, LXCHOOK_MOUNT, LXCHOOK_AUTODEV, > @@ -285,13 +284,10 @@ struct lxc_conf { > char *ttydir; > int close_all_fds; > struct lxc_list hooks[NUM_LXC_HOOKS]; > -#if HAVE_APPARMOR > - char *aa_profile; > -#endif > > -#if HAVE_APPARMOR /* || HAVE_SELINUX || HAVE_SMACK */ > + char *lsm_aa_profile; > + char *lsm_se_context; > int lsm_umount_proc; > -#endif > char *seccomp; // filename with the seccomp rules > #if HAVE_SCMP_FILTER_CTX > scmp_filter_ctx *seccomp_ctx; > diff --git a/src/lxc/confile.c b/src/lxc/confile.c > index b378c3a..a623d88 100644 > --- a/src/lxc/confile.c > +++ b/src/lxc/confile.c > @@ -57,9 +57,8 @@ static int config_pts(const char *, const char *, struct > lxc_conf *); > static int config_tty(const char *, const char *, struct lxc_conf *); > static int config_ttydir(const char *, const char *, struct lxc_conf *); > static int config_kmsg(const char *, const char *, struct lxc_conf *); > -#if HAVE_APPARMOR > -static int config_aa_profile(const char *, const char *, struct lxc_conf *); > -#endif > +static int config_lsm_aa_profile(const char *, const char *, struct lxc_conf > *); > +static int config_lsm_se_context(const char *, const char *, struct lxc_conf > *); > static int config_cgroup(const char *, const char *, struct lxc_conf *); > static int config_idmap(const char *, const char *, struct lxc_conf *); > static int config_loglevel(const char *, const char *, struct lxc_conf *); > @@ -100,9 +99,8 @@ static struct lxc_config_t config[] = { > { "lxc.tty", config_tty }, > { "lxc.devttydir", config_ttydir }, > { "lxc.kmsg", config_kmsg }, > -#if HAVE_APPARMOR > - { "lxc.aa_profile", config_aa_profile }, > -#endif > + { "lxc.aa_profile", config_lsm_aa_profile }, > + { "lxc.se_context", config_lsm_se_context }, > { "lxc.cgroup", config_cgroup }, > { "lxc.id_map", config_idmap }, > { "lxc.loglevel", config_loglevel }, > @@ -967,9 +965,8 @@ static int config_kmsg(const char *key, const char *value, > return 0; > } > > -#if HAVE_APPARMOR > -static int config_aa_profile(const char *key, const char *value, > - struct lxc_conf *lxc_conf) > +static int config_lsm_aa_profile(const char *key, const char *value, > + struct lxc_conf *lxc_conf) > { > char *path; > > @@ -981,13 +978,32 @@ static int config_aa_profile(const char *key, const > char *value, > return -1; > } > > - if (lxc_conf->aa_profile) > - free(lxc_conf->aa_profile); > - lxc_conf->aa_profile = path; > + if (lxc_conf->lsm_aa_profile) > + free(lxc_conf->lsm_aa_profile); > + lxc_conf->lsm_aa_profile = path; > + > + return 0; > +} > + > +static int config_lsm_se_context(const char *key, const 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; > + } > + > + if (lxc_conf->lsm_se_context) > + free(lxc_conf->lsm_se_context); > + lxc_conf->lsm_se_context = path; > > return 0; > } > -#endif > > static int config_logfile(const char *key, const char *value, > struct lxc_conf *lxc_conf) > @@ -1913,10 +1929,10 @@ int lxc_get_config_item(struct lxc_conf *c, const > char *key, char *retv, > v = c->ttydir; > else if (strcmp(key, "lxc.arch") == 0) > return lxc_get_arch_entry(c, retv, inlen); > -#if HAVE_APPARMOR > else if (strcmp(key, "lxc.aa_profile") == 0) > - v = c->aa_profile; > -#endif > + v = c->lsm_aa_profile; > + else if (strcmp(key, "lxc.se_context") == 0) > + v = c->lsm_se_context; > else if (strcmp(key, "lxc.logfile") == 0) > v = lxc_log_get_file(); > else if (strcmp(key, "lxc.loglevel") == 0) > @@ -2000,10 +2016,10 @@ void write_config(FILE *fout, struct lxc_conf *c) > default: break; > } > #endif > -#if HAVE_APPARMOR > - if (c->aa_profile) > - fprintf(fout, "lxc.aa_profile = %s\n", c->aa_profile); > -#endif > + if (c->lsm_aa_profile) > + fprintf(fout, "lxc.aa_profile = %s\n", c->lsm_aa_profile); > + if (c->lsm_se_context) > + fprintf(fout, "lxc.se_context = %s\n", c->lsm_se_context); > if (c->loglevel != LXC_LOG_PRIORITY_NOTSET) > fprintf(fout, "lxc.loglevel = %s\n", > lxc_log_priority_to_string(c->loglevel)); > if (c->logfile) > diff --git a/src/lxc/lsm/apparmor.c b/src/lxc/lsm/apparmor.c > new file mode 100644 > index 0000000..c13613a > --- /dev/null > +++ b/src/lxc/lsm/apparmor.c > @@ -0,0 +1,179 @@ > +/* apparmor > + * > + * Copyright © 2012 Serge Hallyn <serge.hal...@ubuntu.com>. > + * Copyright © 2012 Canonical Ltd. > + * > + * 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 > + */ > + > +#include <stdio.h> > +#include <stdlib.h> > +#include <unistd.h> > +#include <errno.h> > +#include <sys/types.h> > +#include <sys/stat.h> > +#include <sys/mount.h> > +#include <sys/apparmor.h> > +#include "log.h" > +#include "lxclock.h" > +#include "lsm/lsm.h" > + > +lxc_log_define(lxc_apparmor, lxc); > + > +#define AA_DEF_PROFILE "lxc-container-default" > +#define AA_MOUNT_RESTR "/sys/kernel/security/apparmor/features/mount/mask" > +#define AA_ENABLED_FILE "/sys/module/apparmor/parameters/enabled" > + > +/* aa_getcon is not working right now. Use our hand-rolled version below */ > +static int apparmor_enabled(void) > +{ > + struct stat statbuf; > + FILE *fin; > + char e; > + int ret; > + > + ret = stat(AA_MOUNT_RESTR, &statbuf); > + if (ret != 0) > + return 0; > + process_lock(); > + fin = fopen(AA_ENABLED_FILE, "r"); > + process_unlock(); > + if (!fin) > + return 0; > + ret = fscanf(fin, "%c", &e); > + process_lock(); > + fclose(fin); > + process_unlock(); > + if (ret == 1 && e == 'Y') > + return 1; > + return 0; > +} > + > +static char *apparmor_process_label_get(pid_t pid) > +{ > + char path[100], *space; > + int ret; > + 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: > + process_lock(); > + f = fopen(path, "r"); > + process_unlock(); > + if (!f) { > + SYSERROR("opening %s\n", path); > + if (buf) > + free(buf); > + return NULL; > + } > + sz += 1024; > + buf = realloc(buf, sz); > + if (!buf) { > + ERROR("out of memory"); > + process_lock(); > + fclose(f); > + process_unlock(); > + return NULL; > + } > + memset(buf, 0, sz); > + ret = fread(buf, 1, sz - 1, f); > + process_lock(); > + fclose(f); > + process_unlock(); > + if (ret < 0) { > + ERROR("reading %s\n", path); > + free(buf); > + return NULL; > + } > + if (ret >= sz) > + goto again; > + space = index(buf, '\n'); > + if (space) > + *space = '\0'; > + space = index(buf, ' '); > + if (space) > + *space = '\0'; > + return buf; > +} > + > +static int apparmor_am_unconfined(void) > +{ > + char *p = apparmor_process_label_get(getpid()); > + int ret = 0; > + if (!p || strcmp(p, "unconfined") == 0) > + ret = 1; > + if (p) > + free(p); > + return ret; > +} > + > +/* > + * apparmor_process_label_set: Set AppArmor process profile > + * > + * @label : the profile to set > + * @default : use the default profile if label is NULL > + * > + * Returns 0 on success, < 0 on failure > + * > + * Notes: This relies on /proc being available. The new context > + * will take effect immediately. > + */ > +static int apparmor_process_label_set(const char *label, int use_default) > +{ > + if (!apparmor_enabled()) > + return 0; > + > + if (!label) { > + if (use_default) > + label = AA_DEF_PROFILE; > + else > + return 0; > + } > + > + if (strcmp(label, "unconfined") == 0 && apparmor_am_unconfined()) { > + INFO("apparmor profile unchanged"); > + return 0; > + } > + > + /* XXX: instant instead of aa_change_onexec(), may be used by attach > + * when using a function that doesn't exec > + */ > + if (aa_change_profile(label) < 0) { > + SYSERROR("failed to change apparmor profile to %s", label); > + return -1; > + } > + > + INFO("changed apparmor profile to %s", label); > + return 0; > +} > + > +static struct lsm_drv apparmor_drv = { > + .name = "AppArmor", > + .process_label_get = apparmor_process_label_get, > + .process_label_set = apparmor_process_label_set, > +}; > + > +struct lsm_drv *lsm_apparmor_drv_init(void) > +{ > + if (!apparmor_enabled()) > + return NULL; > + return &apparmor_drv; > +} > diff --git a/src/lxc/lsm/lsm.c b/src/lxc/lsm/lsm.c > new file mode 100644 > index 0000000..3974f11 > --- /dev/null > +++ b/src/lxc/lsm/lsm.c > @@ -0,0 +1,156 @@ > +/* > + * lxc: linux Container library > + * > + * Authors: > + * Copyright © 2012 Serge Hallyn <serge.hal...@ubuntu.com> > + * Copyright © 2012 Canonical Ltd. > + * Dwight Engen <dwight.en...@oracle.com> > + * > + * 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 HAVE_APPARMOR || HAVE_SELINUX > + > +#include <errno.h> > +#include <stdlib.h> > +#include <unistd.h> > +#include <sys/mount.h> > +#include <sys/param.h> > + > +#include "conf.h" > +#include "log.h" > +#include "lsm/lsm.h" > + > +lxc_log_define(lxc_lsm, lxc); > + > +static struct lsm_drv *drv = NULL; > + > +extern struct lsm_drv *lsm_apparmor_drv_init(void); > +extern struct lsm_drv *lsm_selinux_drv_init(void); > +extern struct lsm_drv *lsm_nop_drv_init(void); > + > +__attribute__((constructor)) > +void lsm_init(void) > +{ > + if (drv) { > + INFO("LSM security driver %s", drv->name); > + return; > + } > + > + #if HAVE_APPARMOR > + drv = lsm_apparmor_drv_init(); > + #endif > + #if HAVE_SELINUX > + if (!drv) > + drv = lsm_selinux_drv_init(); > + #endif > + > + if (!drv) > + drv = lsm_nop_drv_init(); > + INFO("Initialized LSM security driver %s", drv->name); > +} > + > +char *lsm_process_label_get(pid_t pid) > +{ > + if (!drv) { > + ERROR("LSM driver not inited"); > + return NULL; > + } > + return drv->process_label_get(pid); > +} > + > +int lsm_process_label_set(const char *label, int use_default) > +{ > + if (!drv) { > + ERROR("LSM driver not inited"); > + return -1; > + } > + return drv->process_label_set(label, use_default); > +} > + > +/* > + * _lsm_mount_proc: Mount /proc inside container to enable > + * security domain transition > + * > + * @rootfs : the rootfs where proc should be mounted > + * > + * Returns < 0 on failure, 0 if the correct proc was already mounted > + * and 1 if a new proc was mounted. > + */ > +static int _lsm_proc_mount(const char *rootfs) > +{ > + char path[MAXPATHLEN]; > + char link[20]; > + int linklen, ret; > + > + ret = snprintf(path, MAXPATHLEN, "%s/proc/self", rootfs); > + 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'", getpid(), link); > + ret = snprintf(path, MAXPATHLEN, "%s/proc", rootfs); > + 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 in container for security transition"); > + return 1; > +} > + > +int lsm_proc_mount(struct lxc_conf *lxc_conf) > +{ > + int mounted; > + > + if (!drv || strcmp(drv->name, "nop") == 0) > + return 0; > + > + if (lxc_conf->rootfs.path == NULL || strlen(lxc_conf->rootfs.path) == > 0) { > + if (mount("proc", "/proc", "proc", 0, NULL)) { > + SYSERROR("Failed mounting /proc, proceeding"); > + mounted = 0; > + } else > + mounted = 1; > + } else > + mounted = _lsm_proc_mount(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; > + } > + return 0; > +} > + > +void lsm_proc_unmount(struct lxc_conf *lxc_conf) > +{ > + if (lxc_conf->lsm_umount_proc == 1) { > + umount("/proc"); > + lxc_conf->lsm_umount_proc = 0; > + } > +} > +#endif > diff --git a/src/lxc/lsm/lsm.h b/src/lxc/lsm/lsm.h > new file mode 100644 > index 0000000..2a82c66 > --- /dev/null > +++ b/src/lxc/lsm/lsm.h > @@ -0,0 +1,52 @@ > +/* > + * lxc: linux Container library > + * > + * Copyright © 2013 Oracle. > + * > + * Authors: > + * Dwight Engen <dwight.en...@oracle.com> > + * > + * 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 > + */ > + > +#ifndef __lxc_lsm_h > +#define __lxc_lsm_h > + > +struct lxc_conf; > + > +#include <sys/types.h> > + > +struct lsm_drv { > + const char *name; > + > + char *(*process_label_get)(pid_t pid); > + int (*process_label_set)(const char *label, int use_default); > +}; > + > +#if HAVE_APPARMOR || HAVE_SELINUX > +void lsm_init(void); > +char *lsm_process_label_get(pid_t pid); > +int lsm_process_label_set(const char *label, int use_default); > +int lsm_proc_mount(struct lxc_conf *lxc_conf); > +void lsm_proc_unmount(struct lxc_conf *lxc_conf); > +#else > +static inline void lsm_init(void) { } > +static inline char *lsm_process_label_get(pid_t pid) { return NULL; } > +static inline int lsm_process_label_set(char *label, int use_default) { > return 0; } > +static inline int lsm_proc_mount(struct lxc_conf *lxc_conf) { return 0; } > +static inline void lsm_proc_unmount(struct lxc_conf *lxc_conf) { } > +#endif > + > +#endif > diff --git a/src/lxc/lsm/nop.c b/src/lxc/lsm/nop.c > new file mode 100644 > index 0000000..9184e6b > --- /dev/null > +++ b/src/lxc/lsm/nop.c > @@ -0,0 +1,46 @@ > +/* > + * lxc: linux Container library > + * > + * Copyright © 2013 Oracle. > + * > + * Authors: > + * Dwight Engen <dwight.en...@oracle.com> > + * > + * 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 > + */ > + > +#include <stdlib.h> > +#include "lsm/lsm.h" > + > +static char *nop_process_label_get(pid_t pid) > +{ > + return NULL; > +} > + > +static int nop_process_label_set(const char *label, int use_default) > +{ > + return 0; > +} > + > +static struct lsm_drv nop_drv = { > + .name = "nop", > + .process_label_get = nop_process_label_get, > + .process_label_set = nop_process_label_set, > +}; > + > +struct lsm_drv *lsm_nop_drv_init(void) > +{ > + return &nop_drv; > +} > diff --git a/src/lxc/lsm/selinux.c b/src/lxc/lsm/selinux.c > new file mode 100644 > index 0000000..6e44e8b > --- /dev/null > +++ b/src/lxc/lsm/selinux.c > @@ -0,0 +1,101 @@ > +/* > + * lxc: linux Container library > + * > + * Copyright © 2013 Oracle. > + * > + * Authors: > + * Dwight Engen <dwight.en...@oracle.com> > + * > + * This library is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2, as > + * published by the Free Software Foundation. > + * > + * This program 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 General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, write to the Free Software Foundation, Inc., > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. > + */ > + > +#include <errno.h> > +#include <stdlib.h> > +#include <sys/types.h> > +#include <unistd.h> > +#include <selinux/selinux.h> > +#include "log.h" > +#include "lsm/lsm.h" > + > +#define DEFAULT_LABEL "unconfined_t" > + > +lxc_log_define(lxc_lsm_selinux, lxc); > + > +/* > + * selinux_process_label_get: Get SELinux context of a process > + * > + * @pid : the pid to get, or 0 for self > + * > + * Returns the context of the given pid. The caller must free() > + * the returned string. > + * > + * Note that this relies on /proc being available. > + */ > +static char *selinux_process_label_get(pid_t pid) > +{ > + security_context_t ctx; > + char *label; > + > + if (getpidcon_raw(pid, &ctx) < 0) { > + SYSERROR("failed to get SELinux context for pid %d", pid); > + return NULL; > + } > + label = strdup((char *)ctx); > + freecon(ctx); > + return label; > +} > + > +/* > + * selinux_process_label_set: Set SELinux context of a process > + * > + * @label : the context to set > + * @default : use the default context if label is NULL > + * > + * Returns 0 on success, < 0 on failure > + * > + * Notes: This relies on /proc being available. The new context > + * will take effect on the next exec(2). > + */ > +static int selinux_process_label_set(const char *label, int use_default) > +{ > + if (!label) { > + if (use_default) > + label = DEFAULT_LABEL; > + else > + return -1; > + } > + if (!strcmp(label, "unconfined_t")) > + return 0; > + > + if (setexeccon_raw((char *)label) < 0) { > + SYSERROR("failed to set new SELinux context %s", label); > + return -1; > + } > + > + INFO("changed SELinux context to %s", label); > + return 0; > +} > + > +static struct lsm_drv selinux_drv = { > + .name = "SELinux", > + .process_label_get = selinux_process_label_get, > + .process_label_set = selinux_process_label_set, > +}; > + > +struct lsm_drv *lsm_selinux_drv_init(void) > +{ > + if (!is_selinux_enabled()) > + return NULL; > + return &selinux_drv; > +} > diff --git a/src/lxc/start.c b/src/lxc/start.c > index c968bb1..7538403 100644 > --- a/src/lxc/start.c > +++ b/src/lxc/start.c > @@ -68,10 +68,10 @@ > #include "console.h" > #include "sync.h" > #include "namespace.h" > -#include "apparmor.h" > #include "lxcseccomp.h" > #include "caps.h" > #include "lxclock.h" > +#include "lsm/lsm.h" > > lxc_log_define(lxc_start, lxc); > > @@ -285,7 +285,8 @@ struct lxc_handler *lxc_init(const char *name, struct > lxc_conf *conf, const char > handler->lxcpath = lxcpath; > handler->pinfd = -1; > > - apparmor_handler_init(handler); > + lsm_init(); > + > handler->name = strdup(name); > if (!handler->name) { > ERROR("failed to allocate memory"); > @@ -555,8 +556,16 @@ static int do_start(void *data) > if (lxc_sync_barrier_parent(handler, LXC_SYNC_CGROUP)) > return -1; > > - if (apparmor_load(handler) < 0) > + /* XXX: hmm apparmor switches right away since it uses > + * aa_change_profile() and not aa_change_onexec(). SELinux on the other > + * hand is going to transition on exec(). Is it bad to run the stuff > + * between here and exec() in the more privileged context? > + */ > + if (lsm_process_label_set(handler->conf->lsm_aa_profile ? > + handler->conf->lsm_aa_profile : > + handler->conf->lsm_se_context, 1) < 0) > goto out_warn_father; > + lsm_proc_unmount(handler->conf); > > if (lxc_seccomp_load(handler->conf) != 0) > goto out_warn_father; > diff --git a/src/lxc/start.h b/src/lxc/start.h > index 9bf6024..c35c5c4 100644 > --- a/src/lxc/start.h > +++ b/src/lxc/start.h > @@ -50,9 +50,6 @@ struct lxc_handler { > struct lxc_operations *ops; > void *data; > int sv[2]; > -#if HAVE_APPARMOR > - int aa_enabled; > -#endif > int pinfd; > const char *lxcpath; > struct cgroup_process_info *cgroup; > diff --git a/templates/lxc-oracle.in b/templates/lxc-oracle.in > index 98ea609..c0fcd30 100644 > --- a/templates/lxc-oracle.in > +++ b/templates/lxc-oracle.in > @@ -110,10 +110,8 @@ EOF > # this file has to exist for libvirt/Virtual machine monitor to boot the > container > touch $container_rootfs/etc/mtab > > - # don't put devpts in here, it will already be mounted for us by > lxc/libvirt > + # don't put devpts,proc, nor sysfs in here, it will already be mounted > for us by lxc/libvirt > cat <<EOF > $container_rootfs/etc/fstab > -proc /proc proc nodev,noexec,nosuid 0 0 > -sysfs /sys sysfs defaults 0 0 > EOF > > # remove module stuff for iptables it just shows errors that are not > @@ -404,9 +402,8 @@ lxc.cgroup.devices.allow = c 5:2 rwm # /dev/ptmx pty > master > EOF > > cat <<EOF > $cfg_dir/fstab || die "unable to create $cfg_dir/fstab" > -proc $container_rootfs/proc proc nodev,noexec,nosuid 0 0 > -devpts $container_rootfs/dev/pts devpts defaults 0 0 > -sysfs $container_rootfs/sys sysfs defaults 0 0 > +proc proc proc nodev,noexec,nosuid 0 0 > +sysfs sys sysfs defaults 0 0 > EOF > } > > -- > 1.8.1.4 > > > ------------------------------------------------------------------------------ > October Webinars: Code for Performance > Free Intel webinars can help you accelerate application performance. > Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from > the latest Intel processors and coprocessors. See abstracts and register > > http://pubads.g.doubleclick.net/gampad/clk?id=60133471&iu=/4140/ostg.clktrk > _______________________________________________ > Lxc-devel mailing list > Lxc-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/lxc-devel ------------------------------------------------------------------------------ October Webinars: Code for Performance Free Intel webinars can help you accelerate application performance. Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from the latest Intel processors and coprocessors. See abstracts and register > http://pubads.g.doubleclick.net/gampad/clk?id=60133471&iu=/4140/ostg.clktrk _______________________________________________ Lxc-devel mailing list Lxc-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/lxc-devel