[lxc-devel] [PATCH RFC] apparmor: improve behavior when kernel lacks mount restrictions
Serge Hallyn
serge.hallyn at ubuntu.com
Fri Sep 19 22:17:25 UTC 2014
Quoting Stéphane Graber (stgraber at ubuntu.com):
> On Sun, Sep 14, 2014 at 03:49:32AM +0000, Serge Hallyn wrote:
> > (If we go this route we can also drop the whole lsm_label_get()
> > method and the lsm_label field in the attach context info)
>
> I'm not too familiar with the lsm code and I tend to get lost in there,
> so just a few questions to confirm there's no hidden problems:
> - We can drop lsm_label_get() and lsb_label because we'll have lxc_conf
> everywhere instead?
Right. Except,
> - What happens for attach, do we need a matching code change or is it
> going through the same lsm_* codepath and so will also parse lxc_conf
> and respect the new key if set?
I thought I had handled attach, but actually what I have is not quite
right. In particular, if the container configuration file says
lxc.aa_profile = p1, but you started the container with
lxc-start -n u1 -s lxc.aa_profile=p2
then you'll be attached in profile p1.
So i guess we do still need the lsm_label_get(), and we'll have to
pass a static label in from attach like we did before.
I'm afraid I'm not up to rewriting the patch tonight, so this'll just
have to miss the next release.
> > Apparmor policies require mount restrictions to fullfill many of
> > their promises - for instance if proc can be mounted anywhere,
> > then 'deny /proc/sysrq-trigger w' prevents only accidents, not
> > malice.
> >
> > The mount restrictions are not available in the upstream kernel.
> > We can detect their presence through /sys. In the past, when
> > we detected it missing, we would not enable apparmor. But that
> > prevents apparmor from helping to prevent accidents.
> >
> > At the same time, if the user accidentaly boots a kernel which
> > has regressed, we do not want them starting the container thinking
> > they are more protected than they are.
> >
> > This patch:
> >
> > 1. adds a lxc.aa_allow_incomplete = 1 container config flag. If
> > not set, then any container which is not set to run unconfined
> > will refuse to run. If set, then the container will run with
> > apparmor protection.
> >
> > 2. to pass this flag to the apparmor driver, we pass the container
> > configuration (lxc_conf) to the lsm_label_set hook, rather than
> > just the label.
> >
> > 3. add a testcase. To test the case were a kernel does not
> > provide mount restrictions, we mount an empty directory over
> > the /sys/kernel/security/apparmor/features/mount directory. In
> > order to have that not be unmounted in a new namespace, we must
> > test using unprivileged containers (who cannot remove bind mounts
> > which hide existing mount contents).
>
> Took me a while to figure out exactly what this covers, I guess that's
> the case where:
> - policy contains mount entries
> - parser support the mount stanza
> - kernel doesn't support it
>
> Because the other cases we usually run into are those where:
> - policy contains new fancy stanza
> - parser doesn't support it
> - kernel doesn't support it
>
> In which case the whole profile fails to load and I believe we already
> fail in that case with an appropriate error (rather than start
> unconfined).
>
> >
> > Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
> > ---
> > src/lxc/attach.c | 2 +-
> > src/lxc/conf.h | 1 +
> > src/lxc/confile.c | 14 +++
> > src/lxc/lsm/apparmor.c | 32 +++++--
> > src/lxc/lsm/lsm.c | 4 +-
> > src/lxc/lsm/lsm.h | 8 +-
> > src/lxc/lsm/nop.c | 2 +-
> > src/lxc/lsm/selinux.c | 6 +-
> > src/lxc/start.c | 7 +-
> > src/tests/Makefile.am | 1 +
> > src/tests/lxc-test-apparmor-mount | 189 ++++++++++++++++++++++++++++++++++++++
> > 11 files changed, 245 insertions(+), 21 deletions(-)
> > create mode 100755 src/tests/lxc-test-apparmor-mount
> >
> > diff --git a/src/lxc/attach.c b/src/lxc/attach.c
> > index 923c497..9d92240 100644
> > --- a/src/lxc/attach.c
> > +++ b/src/lxc/attach.c
> > @@ -1043,7 +1043,7 @@ static int attach_child_main(void* data)
> > int on_exec;
> >
> > on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0;
> > - ret = lsm_process_label_set(init_ctx->lsm_label, 0, on_exec);
> > + ret = lsm_process_label_set(init_ctx->container->lxc_conf, 0, on_exec);
> > if (ret < 0) {
> > rexit(-1);
> > }
> > diff --git a/src/lxc/conf.h b/src/lxc/conf.h
> > index df66f99..97d9f91 100644
> > --- a/src/lxc/conf.h
> > +++ b/src/lxc/conf.h
> > @@ -311,6 +311,7 @@ struct lxc_conf {
> > struct lxc_list hooks[NUM_LXC_HOOKS];
> >
> > char *lsm_aa_profile;
> > + int lsm_aa_allow_incomplete;
> > char *lsm_se_context;
> > int tmp_umount_proc;
> > char *seccomp; // filename with the seccomp rules
> > diff --git a/src/lxc/confile.c b/src/lxc/confile.c
> > index 5de1241..af55feb 100644
> > --- a/src/lxc/confile.c
> > +++ b/src/lxc/confile.c
> > @@ -58,6 +58,7 @@ 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 *);
> > static int config_lsm_aa_profile(const char *, const char *, struct lxc_conf *);
> > +static int config_lsm_aa_incomplete(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 *);
> > @@ -108,6 +109,7 @@ static struct lxc_config_t config[] = {
> > { "lxc.devttydir", config_ttydir },
> > { "lxc.kmsg", config_kmsg },
> > { "lxc.aa_profile", config_lsm_aa_profile },
> > + { "lxc.aa_allow_incomplete", config_lsm_aa_incomplete },
> > { "lxc.se_context", config_lsm_se_context },
> > { "lxc.cgroup", config_cgroup },
> > { "lxc.id_map", config_idmap },
> > @@ -1145,6 +1147,16 @@ static int config_lsm_aa_profile(const char *key, const char *value,
> > return config_string_item(&lxc_conf->lsm_aa_profile, value);
> > }
> >
> > +static int config_lsm_aa_incomplete(const char *key, const char *value,
> > + struct lxc_conf *lxc_conf)
> > +{
> > + int v = atoi(value);
> > +
> > + lxc_conf->lsm_aa_allow_incomplete = v == 1 ? 1 : 0;
> > +
> > + return 0;
> > +}
> > +
> > static int config_lsm_se_context(const char *key, const char *value,
> > struct lxc_conf *lxc_conf)
> > {
> > @@ -2257,6 +2269,8 @@ int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv,
> > return lxc_get_arch_entry(c, retv, inlen);
> > else if (strcmp(key, "lxc.aa_profile") == 0)
> > v = c->lsm_aa_profile;
> > + else if (strcmp(key, "lxc.aa_allow_incomplete") == 0)
> > + return lxc_get_conf_int(c, retv, inlen, c->lsm_aa_allow_incomplete);
> > else if (strcmp(key, "lxc.se_context") == 0)
> > v = c->lsm_se_context;
> > else if (strcmp(key, "lxc.logfile") == 0)
> > diff --git a/src/lxc/lsm/apparmor.c b/src/lxc/lsm/apparmor.c
> > index f4c8d26..3e98a38 100644
> > --- a/src/lxc/lsm/apparmor.c
> > +++ b/src/lxc/lsm/apparmor.c
> > @@ -29,6 +29,7 @@
> >
> > #include "log.h"
> > #include "lsm/lsm.h"
> > +#include "conf.h"
> >
> > lxc_log_define(lxc_apparmor, lxc);
> >
> > @@ -39,17 +40,23 @@ static int aa_enabled = 0;
> > #define AA_MOUNT_RESTR "/sys/kernel/security/apparmor/features/mount/mask"
> > #define AA_ENABLED_FILE "/sys/module/apparmor/parameters/enabled"
> >
> > +static int mount_feature_enabled(void)
> > +{
> > + struct stat statbuf;
> > + int ret;
> > + ret = stat(AA_MOUNT_RESTR, &statbuf);
> > + if (ret != 0)
> > + return 0;
> > + return 1;
> > +}
> > +
> > /* 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;
> > fin = fopen(AA_ENABLED_FILE, "r");
> > if (!fin)
> > return 0;
> > @@ -131,9 +138,11 @@ static int apparmor_am_unconfined(void)
> > *
> > * Notes: This relies on /proc being available.
> > */
> > -static int apparmor_process_label_set(const char *label, int use_default,
> > +static int apparmor_process_label_set(struct lxc_conf *conf, int use_default,
> > int on_exec)
> > {
> > + const char *label = conf->lsm_aa_profile;
> > +
> > if (!aa_enabled)
> > return 0;
> >
> > @@ -141,9 +150,20 @@ static int apparmor_process_label_set(const char *label, int use_default,
> > if (use_default)
> > label = AA_DEF_PROFILE;
> > else
> > - return 0;
> > + label = "unconfined";
> > + }
> > +
> > + if (!mount_feature_enabled() && strcmp(label, "unconfined") != 0) {
> > + WARN("Incomplete AppArmor support in your kernel");
> > + if (!conf->lsm_aa_allow_incomplete) {
> > + ERROR("If you really want to start this container, set");
> > + ERROR("lxc.aa_allow_incomplete = 1");
> > + ERROR("in your container configuration file");
> > + return -1;
> > + }
> > }
> >
> > +
> > if (strcmp(label, "unconfined") == 0 && apparmor_am_unconfined()) {
> > INFO("apparmor profile unchanged");
> > return 0;
> > diff --git a/src/lxc/lsm/lsm.c b/src/lxc/lsm/lsm.c
> > index c994046..54b404c 100644
> > --- a/src/lxc/lsm/lsm.c
> > +++ b/src/lxc/lsm/lsm.c
> > @@ -85,13 +85,13 @@ char *lsm_process_label_get(pid_t pid)
> > return drv->process_label_get(pid);
> > }
> >
> > -int lsm_process_label_set(const char *label, int use_default, int on_exec)
> > +int lsm_process_label_set(struct lxc_conf *conf, int use_default, int on_exec)
> > {
> > if (!drv) {
> > ERROR("LSM driver not inited");
> > return -1;
> > }
> > - return drv->process_label_set(label, use_default, on_exec);
> > + return drv->process_label_set(conf, use_default, on_exec);
> > }
> >
> > #endif
> > diff --git a/src/lxc/lsm/lsm.h b/src/lxc/lsm/lsm.h
> > index 93f5b87..0d21b4c 100644
> > --- a/src/lxc/lsm/lsm.h
> > +++ b/src/lxc/lsm/lsm.h
> > @@ -33,7 +33,7 @@ struct lsm_drv {
> >
> > int (*enabled)(void);
> > char *(*process_label_get)(pid_t pid);
> > - int (*process_label_set)(const char *label, int use_default,
> > + int (*process_label_set)(struct lxc_conf *conf, int use_default,
> > int on_exec);
> > };
> >
> > @@ -42,13 +42,15 @@ 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, int use_default, int on_exec);
> > +int lsm_process_label_set(struct lxc_conf *conf,
> > + int use_default, int 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, int use_default, int on_exec) { return 0; }
> > +static inline int lsm_process_label_set(struct lxc-conf *conf,
> > + int use_default, int on_exec) { return 0; }
> > #endif
> >
> > #endif
> > diff --git a/src/lxc/lsm/nop.c b/src/lxc/lsm/nop.c
> > index e5db124..5e10f4e 100644
> > --- a/src/lxc/lsm/nop.c
> > +++ b/src/lxc/lsm/nop.c
> > @@ -29,7 +29,7 @@ static char *nop_process_label_get(pid_t pid)
> > return NULL;
> > }
> >
> > -static int nop_process_label_set(const char *label, int use_default,
> > +static int nop_process_label_set(struct lxc_conf *conf, int use_default,
> > int on_exec)
> > {
> > return 0;
> > diff --git a/src/lxc/lsm/selinux.c b/src/lxc/lsm/selinux.c
> > index f8dad95..9e33055 100644
> > --- a/src/lxc/lsm/selinux.c
> > +++ b/src/lxc/lsm/selinux.c
> > @@ -29,6 +29,7 @@
> >
> > #include "log.h"
> > #include "lsm/lsm.h"
> > +#include "conf.h"
> >
> > #define DEFAULT_LABEL "unconfined_t"
> >
> > @@ -61,7 +62,7 @@ static char *selinux_process_label_get(pid_t pid)
> > /*
> > * selinux_process_label_set: Set SELinux context of a process
> > *
> > - * @label : the context to set
> > + * @conf : the container configuration
> > * @default : use the default context if label is NULL
> > * @on_exec : the new context will take effect on exec(2) not immediately
> > *
> > @@ -69,9 +70,10 @@ static char *selinux_process_label_get(pid_t pid)
> > *
> > * Notes: This relies on /proc being available.
> > */
> > -static int selinux_process_label_set(const char *label, int use_default,
> > +static int selinux_process_label_set(struct lxc_conf *conf, int use_default,
> > int on_exec)
> > {
> > + const char *label = conf->lsm_se_context;
> > if (!label) {
> > if (use_default)
> > label = DEFAULT_LABEL;
> > diff --git a/src/lxc/start.c b/src/lxc/start.c
> > index d9fbc8c..d4dcd56 100644
> > --- a/src/lxc/start.c
> > +++ b/src/lxc/start.c
> > @@ -615,7 +615,6 @@ static int do_start(void *data)
> > {
> > struct lxc_list *iterator;
> > struct lxc_handler *handler = data;
> > - const char *lsm_label = NULL;
> >
> > if (sigprocmask(SIG_SETMASK, &handler->oldmask, NULL)) {
> > SYSERROR("failed to set sigprocmask");
> > @@ -695,11 +694,7 @@ static int do_start(void *data)
> > return -1;
> >
> > /* Set the label to change to when we exec(2) the container's init */
> > - if (!strcmp(lsm_name(), "AppArmor"))
> > - lsm_label = handler->conf->lsm_aa_profile;
> > - else if (!strcmp(lsm_name(), "SELinux"))
> > - lsm_label = handler->conf->lsm_se_context;
> > - if (lsm_process_label_set(lsm_label, 1, 1) < 0)
> > + if (lsm_process_label_set(handler->conf, 1, 1) < 0)
> > goto out_warn_father;
> >
> > /* Some init's such as busybox will set sane tty settings on stdin,
> > diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
> > index 35bc1b3..e0969eb 100644
> > --- a/src/tests/Makefile.am
> > +++ b/src/tests/Makefile.am
> > @@ -52,6 +52,7 @@ bin_SCRIPTS = lxc-test-autostart
> >
> > if DISTRO_UBUNTU
> > bin_SCRIPTS += \
> > + lxc-test-apparmor-mount \
> > lxc-test-checkpoint-restore \
> > lxc-test-ubuntu \
> > lxc-test-unpriv \
> > diff --git a/src/tests/lxc-test-apparmor-mount b/src/tests/lxc-test-apparmor-mount
> > new file mode 100755
> > index 0000000..503381e
> > --- /dev/null
> > +++ b/src/tests/lxc-test-apparmor-mount
> > @@ -0,0 +1,189 @@
> > +#!/bin/sh
> > +
> > +# apparmor_mount: test proper handling of apparmor in kernels
> > +# without mount features
> > +
> > +# These require the ubuntu lxc package to be installed.
> > +
> > +# This program 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
> > +
> > +# This test assumes an Ubuntu host
> > +
> > +set -e
> > +
> > +FAIL() {
> > + echo -n "Failed " >&2
> > + echo "$*" >&2
> > + exit 1
> > +}
> > +
> > +run_cmd() {
> > + sudo -i -u $TUSER \
> > + env http_proxy=${http_proxy:-} https_proxy=${https_proxy:-} \
> > + XDG_RUNTIME_DIR=/run/user/$(id -u $TUSER) $*
> > +}
> > +
> > +DONE=0
> > +MOUNTSR=/sys/kernel/security/apparmor/features/mount
> > +dnam=`mktemp -d`
> > +cname=`basename $dnam`
> > +cleanup() {
> > + run_cmd lxc-destroy -f -n $cname || true
> > + umount -l $MOUNTSR || true
> > + rmdir $dnam || true
> > + pkill -u $(id -u $TUSER) -9
> > + sed -i '/lxcunpriv/d' /run/lxc/nics /etc/lxc/lxc-usernet
> > + sed -i '/^lxcunpriv:/d' /etc/subuid /etc/subgid
> > + rm -Rf $HDIR /run/user/$(id -u $TUSER)
> > + deluser $TUSER
> > + if [ $DONE -eq 0 ]; then
> > + echo "FAIL"
> > + exit 1
> > + fi
> > + echo "PASS"
> > +}
> > +
> > +trap cleanup exit
> > +
> > +# Only run on a normally configured ubuntu lxc system
> > +if [ ! -d /sys/class/net/lxcbr0 ]; then
> > + echo "lxcbr0 is not configured."
> > + exit 1
> > +fi
> > +if [ "$(id -u)" != "0" ]; then
> > + echo "ERROR: Must run as root."
> > + exit 1
> > +fi
> > +
> > +# This would be much simpler if we could run it as
> > +# root. However, in order to not have the bind mount
> > +# of an empty directory over the securitfs 'mount' directory
> > +# be removed, we need to do this as non-root.
> > +
> > +which newuidmap >/dev/null 2>&1 || { echo "'newuidmap' command is missing" >&2; exit 1; }
> > +# create a test user
> > +TUSER=lxcunpriv
> > +HDIR=/home/$TUSER
> > +
> > +ARCH=i386
> > +if type dpkg >/dev/null 2>&1; then
> > + ARCH=$(dpkg --print-architecture)
> > +fi
> > +
> > +deluser $TUSER && rm -Rf $HDIR || true
> > +useradd $TUSER
> > +
> > +mkdir -p $HDIR
> > +echo "$TUSER veth lxcbr0 2" > /etc/lxc/lxc-usernet
> > +sed -i '/^lxcunpriv:/d' /etc/subuid /etc/subgid
> > +
> > +usermod -v 910000-919999 -w 910000-919999 $TUSER
> > +
> > +mkdir -p $HDIR/.config/lxc/
> > +cat > $HDIR/.config/lxc/default.conf << EOF
> > +lxc.network.type = veth
> > +lxc.network.link = lxcbr0
> > +lxc.id_map = u 0 910000 9999
> > +lxc.id_map = g 0 910000 9999
> > +EOF
> > +chown -R $TUSER: $HDIR
> > +
> > +mkdir -p /run/user/$(id -u $TUSER)
> > +chown -R $TUSER: /run/user/$(id -u $TUSER)
> > +
> > +cd $HDIR
> > +
> > +cgm create all $TUSER
> > +cgm chown all $TUSER $(id -u $TUSER) $(id -g $TUSER)
> > +cgm movepid all $TUSER $$
> > +
> > +run_cmd mkdir -p $HDIR/.cache/lxc
> > +[ -d /var/cache/lxc/download ] && \
> > + cp -R /var/cache/lxc/download $HDIR/.cache/lxc && \
> > + chown -R $TUSER: $HDIR/.cache/lxc
> > +
> > +run_cmd lxc-create -t download -n $cname -- -d ubuntu -r trusty -a $ARCH
> > +
> > +echo "test default confined container"
> > +run_cmd lxc-start -n $cname -d
> > +run_cmd lxc-wait -n $cname -s RUNNING
> > +pid=`run_cmd lxc-info -p -H -n $cname`
> > +profile=`cat /proc/$pid/attr/current`
> > +if [ "x$profile" != "xlxc-container-default (enforce)" ]; then
> > + echo "FAIL: confined container was in profile $profile"
> > + exit 1
> > +fi
> > +run_cmd lxc-stop -n $cname
> > +
> > +echo "test regular unconfined container"
> > +echo "lxc.aa_profile = unconfined" >> $HDIR/.local/share/lxc/$cname/config
> > +run_cmd lxc-start -n $cname -d
> > +run_cmd lxc-wait -n $cname -s RUNNING
> > +pid=`run_cmd lxc-info -p -H -n $cname`
> > +profile=`cat /proc/$pid/attr/current`
> > +if [ "x$profile" != "xunconfined" ]; then
> > + echo "FAIL: unconfined container was in profile $profile"
> > + exit 1
> > +fi
> > +run_cmd lxc-stop -n $cname
> > +
> > +echo "masking $MOUNTSR"
> > +mount --bind $dnam $MOUNTSR
> > +
> > +echo "test default confined container"
> > +sed -i '/aa_profile/d' $HDIR/.local/share/lxc/$cname/config
> > +run_cmd lxc-start -n $cname -d || true
> > +sleep 3
> > +pid=`run_cmd lxc-info -p -H -n $cname` || true
> > +if [ -n "$pid" -a "$pid" != "-1" ]; then
> > + echo "FAIL: confined container started without mount restrictions"
> > + echo "pid was $pid"
> > + exit 1
> > +fi
> > +
> > +echo "test regular unconfined container"
> > +echo "lxc.aa_profile = unconfined" >> $HDIR/.local/share/lxc/$cname/config
> > +run_cmd lxc-start -n $cname -d
> > +run_cmd lxc-wait -n $cname -s RUNNING
> > +pid=`run_cmd lxc-info -p -H -n $cname`
> > +if [ "$pid" = "-1" ]; then
> > + echo "FAIL: unconfined container failed to start without mount restrictions"
> > + exit 1
> > +fi
> > +profile=`cat /proc/$pid/attr/current`
> > +if [ "x$profile" != "xunconfined" ]; then
> > + echo "FAIL: confined container was in profile $profile"
> > + exit 1
> > +fi
> > +run_cmd lxc-stop -n $cname
> > +
> > +echo "testing override"
> > +sed -i '/aa_profile/d' $HDIR/.local/share/lxc/$cname/config
> > +echo "lxc.aa_allow_incomplete = 1" >> $HDIR/.local/share/lxc/$cname/config
> > +run_cmd lxc-start -n $cname -d
> > +run_cmd lxc-wait -n $cname -s RUNNING
> > +pid=`run_cmd lxc-info -p -H -n $cname`
> > +if [ "$pid" = "-1" ]; then
> > + echo "FAIL: excepted container failed to start without mount restrictions"
> > + exit 1
> > +fi
> > +profile=`cat /proc/$pid/attr/current`
> > +if [ "x$profile" != "xlxc-container-default (enforce)" ]; then
> > + echo "FAIL: confined container was in profile $profile"
> > + exit 1
> > +fi
> > +run_cmd lxc-stop -n $cname
> > +
> > +DONE=1
> > --
> > 2.1.0
> >
> > _______________________________________________
> > lxc-devel mailing list
> > lxc-devel at lists.linuxcontainers.org
> > http://lists.linuxcontainers.org/listinfo/lxc-devel
>
> --
> Stéphane Graber
> Ubuntu developer
> http://www.ubuntu.com
> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel
More information about the lxc-devel
mailing list