This patch adds the lxc.mount.auto configuration option that allows the
user to specify that certain standard filesystems should be
automatically pre-mounted when the container is started.

Currently, four things are implemented:

 - /proc          (mounted read-write)
 - /sys           (mounted read-only)
 - /sys/fs/cgroup (special logic, see mailing list discussions)
 - /proc/sysrq-trigger (see below)

/proc/sysrq-trigger may be used from within a container to trigger a
forced host reboot (echo b > /proc/sysrq-trigger) or do other things
that a container shouldn't be able to do. The logic here is to
bind-mount /dev/null over /proc/sysrq-trigger, so that that cannot
happen. This obviously only protects fully if CAP_SYS_ADMIN is not
available inside the container (otherwise that bind-mount could be
removed).

Signed-off-by: Christian Seiler <christ...@iwakd.de>
---
 src/lxc/conf.c    |  111 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/lxc/conf.h    |   14 ++++++-
 src/lxc/confile.c |   63 ++++++++++++++++++++++++++++--
 src/lxc/start.c   |    2 +-
 4 files changed, 183 insertions(+), 7 deletions(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 5f9ae87..364e571 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -72,6 +72,7 @@
 #include "lxc.h"       /* for lxc_cgroup_set() */
 #include "caps.h"       /* for lxc_caps_last_cap() */
 #include "bdev.h"
+#include "cgroup.h"
 
 #if HAVE_APPARMOR
 #include <apparmor.h>
@@ -707,6 +708,89 @@ int pin_rootfs(const char *rootfs)
        return fd;
 }
 
+static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct 
cgroup_process_info *cgroup_info)
+{
+       char *path = NULL;
+       char *dev_null = NULL;
+       int r;
+
+       dev_null = lxc_append_paths(conf->rootfs.mount, "/dev/null");
+       if (!dev_null) {
+               SYSERROR("memory allocation error");
+               goto cleanup;
+       }
+
+       if (flags & LXC_AUTO_PROC) {
+               path = lxc_append_paths(conf->rootfs.mount, "/proc");
+               if (!path) {
+                       SYSERROR("memory allocation error trying to 
automatically mount /proc");
+                       goto cleanup;
+               }
+
+               r = mount("proc", path, "proc", MS_NODEV|MS_NOEXEC|MS_NOSUID, 
NULL);
+               if (r < 0) {
+                       SYSERROR("error mounting /proc");
+                       goto cleanup;
+               }
+
+               free(path);
+               path = NULL;
+       }
+
+       if (flags & LXC_AUTO_PROC_SYSRQ) {
+               path = lxc_append_paths(conf->rootfs.mount, 
"/proc/sysrq-trigger");
+               if (!path) {
+                       SYSERROR("memory allocation error trying to 
automatically mount /proc");
+                       goto cleanup;
+               }
+
+               /* safety measure, mount /dev/null over /proc/sysrq-trigger,
+                * otherwise, a container may trigger a host reboot or such
+                */
+               r = mount(dev_null, path, NULL, MS_BIND, NULL);
+               if (r < 0)
+                       WARN("error mounting /dev/null over 
/proc/sysrq-trigger: %s", strerror(errno));
+
+               free(path);
+               path = NULL;
+       }
+
+       if (flags & LXC_AUTO_SYS) {
+               path = lxc_append_paths(conf->rootfs.mount, "/sys");
+               if (!path) {
+                       SYSERROR("memory allocation error trying to 
automatically mount /sys");
+                       goto cleanup;
+               }
+
+               r = mount("sysfs", path, "sysfs", MS_RDONLY, NULL);
+               if (r < 0) {
+                       SYSERROR("error mounting /sys");
+                       goto cleanup;
+               }
+
+               free(path);
+               path = NULL;
+       }
+
+       if (flags & LXC_AUTO_CGROUP) {
+               r = lxc_setup_mount_cgroup(conf->rootfs.mount, cgroup_info);
+               if (r < 0) {
+                       SYSERROR("error mounting /sys/fs/cgroup");
+                       goto cleanup;
+               }
+       }
+
+       free(dev_null);
+       free(path);
+
+       return 0;
+
+cleanup:
+       free(dev_null);
+       free(path);
+       return -1;
+}
+
 static int mount_rootfs(const char *rootfs, const char *target)
 {
        char absrootfs[MAXPATHLEN];
@@ -2878,7 +2962,7 @@ int uid_shift_ttys(int pid, struct lxc_conf *conf)
        return 0;
 }
 
-int lxc_setup(const char *name, struct lxc_conf *lxc_conf, const char *lxcpath)
+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;
@@ -2911,6 +2995,14 @@ int lxc_setup(const char *name, struct lxc_conf 
*lxc_conf, const char *lxcpath)
                }
        }
 
+       /* do automatic mounts (mainly /proc and /sys), but exclude
+        * those that need to wait until other stuff has finished
+        */
+       if (lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & 
~LXC_AUTO_CGROUP & ~LXC_AUTO_PROC_SYSRQ, cgroup_info) < 0) {
+               ERROR("failed to setup the automatic mounts for '%s'", name);
+               return -1;
+       }
+
        if (setup_mount(&lxc_conf->rootfs, lxc_conf->fstab, name)) {
                ERROR("failed to setup the mounts for '%s'", name);
                return -1;
@@ -2921,6 +3013,15 @@ int lxc_setup(const char *name, struct lxc_conf 
*lxc_conf, const char *lxcpath)
                return -1;
        }
 
+       /* now mount only cgroup, if wanted;
+        * before, /sys could not have been mounted
+        * (is either mounted automatically or via fstab entries)
+        */
+       if (lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & 
LXC_AUTO_CGROUP, cgroup_info) < 0) {
+               ERROR("failed to setup the automatic mounts for '%s'", name);
+               return -1;
+       }
+
        if (run_lxc_hooks(name, "mount", lxc_conf, lxcpath, NULL)) {
                ERROR("failed to run mount hooks for container '%s'.", name);
                return -1;
@@ -2937,6 +3038,14 @@ int lxc_setup(const char *name, struct lxc_conf 
*lxc_conf, const char *lxcpath)
                }
        }
 
+       /* over-mount /proc/sysrq-trigger with /dev/null now, if wanted;
+        * before /dev/null did not necessarily exist
+        */
+       if (lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & 
LXC_AUTO_PROC_SYSRQ, cgroup_info) < 0) {
+               ERROR("failed to setup the automatic mounts for '%s'", name);
+               return -1;
+       }
+
        if (!lxc_conf->is_execute && setup_console(&lxc_conf->rootfs, 
&lxc_conf->console, lxc_conf->ttydir)) {
                ERROR("failed to setup the console for '%s'", name);
                return -1;
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index 5febf12..d99bdfe 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -222,6 +222,16 @@ struct lxc_rootfs {
 };
 
 /*
+ * Automatic mounts for LXC to perform inside the container
+ */
+enum {
+       LXC_AUTO_PROC        = 0x01,   /* /proc */
+       LXC_AUTO_SYS         = 0x02,   /* /sys*/
+       LXC_AUTO_CGROUP      = 0x04,   /* /sys/fs/cgroup */
+       LXC_AUTO_PROC_SYSRQ  = 0x08,   /* /proc/sysrq-trigger over-bind-mounted 
with /dev/null */
+};
+
+/*
  * Defines the global container configuration
  * @rootfs     : root directory to run the container
  * @pivotdir   : pivotdir path, if not set default will be used
@@ -265,6 +275,7 @@ struct lxc_conf {
        struct lxc_list network;
        struct saved_nic *saved_nics;
        int num_savednics;
+       int auto_mounts;
        struct lxc_list mount_list;
        struct lxc_list caps;
        struct lxc_list keepcaps;
@@ -336,8 +347,9 @@ extern int uid_shift_ttys(int pid, struct lxc_conf *conf);
  * Configure the container from inside
  */
 
+struct cgroup_process_info;
 extern int lxc_setup(const char *name, struct lxc_conf *lxc_conf,
-                       const char *lxcpath);
+                       const char *lxcpath, struct cgroup_process_info 
*cgroup_info);
 
 extern void lxc_rename_phys_nics_on_shutdown(struct lxc_conf *conf);
 #endif
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 7904db4..b378c3a 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -1235,11 +1235,60 @@ static int config_fstab(const char *key, const char 
*value,
        return config_path_item(key, value, lxc_conf, &lxc_conf->fstab);
 }
 
+static int config_mount_auto(const char *key, const char *value,
+                            struct lxc_conf *lxc_conf)
+{
+       char *autos, *autoptr, *sptr, *token;
+       static struct { const char *token; int flag; } allowed_auto_mounts[] = {
+               { "proc",   LXC_AUTO_PROC },
+               { "sysrq",  LXC_AUTO_PROC_SYSRQ },
+               { "sys",    LXC_AUTO_SYS },
+               { "cgroup", LXC_AUTO_CGROUP },
+               { NULL, 0 }
+       };
+       int i;
+       int ret = -1;
+
+       if (!strlen(value))
+               return -1;
+
+       autos = strdup(value);
+       if (!autos) {
+               SYSERROR("failed to dup '%s'", value);
+               return -1;
+       }
+
+       for (autoptr = autos; ; autoptr = NULL) {
+                token = strtok_r(autoptr, " \t", &sptr);
+                if (!token) {
+                       ret = 0;
+                        break;
+               }
+
+               for (i = 0; allowed_auto_mounts[i].token; i++) {
+                       if (!strcmp(allowed_auto_mounts[i].token, token))
+                               break;
+               }
+
+               if (!allowed_auto_mounts[i].token) {
+                       ERROR("Invalid filesystem to automount: %s", token);
+                       break;
+               }
+
+               lxc_conf->auto_mounts |= allowed_auto_mounts[i].flag;
+        }
+
+       free(autos);
+
+       return ret;
+}
+
 static int config_mount(const char *key, const char *value,
                        struct lxc_conf *lxc_conf)
 {
        char *fstab_token = "lxc.mount";
        char *token = "lxc.mount.entry";
+       char *auto_token = "lxc.mount.auto";
        char *subkey;
        char *mntelem;
        struct lxc_list *mntlist;
@@ -1247,12 +1296,18 @@ static int config_mount(const char *key, const char 
*value,
        subkey = strstr(key, token);
 
        if (!subkey) {
-               subkey = strstr(key, fstab_token);
+               subkey = strstr(key, auto_token);
 
-               if (!subkey)
-                       return -1;
+               if (!subkey) {
+                       subkey = strstr(key, fstab_token);
+
+                       if (!subkey)
+                               return -1;
+
+                       return config_fstab(key, value, lxc_conf);
+               }
 
-               return config_fstab(key, value, lxc_conf);
+               return config_mount_auto(key, value, lxc_conf);
        }
 
        if (!strlen(subkey))
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 56a2e6b..48a06cf 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -525,7 +525,7 @@ static int do_start(void *data)
        #endif
 
        /* Setup the container, ip, names, utsname, ... */
-       if (lxc_setup(handler->name, handler->conf, handler->lxcpath)) {
+       if (lxc_setup(handler->name, handler->conf, handler->lxcpath, 
handler->cgroup)) {
                ERROR("failed to setup the container");
                goto out_warn_father;
        }
-- 
1.7.10.4


------------------------------------------------------------------------------
How ServiceNow helps IT people transform IT departments:
1. Consolidate legacy IT systems to a single system of record for IT
2. Standardize and globalize service processes across IT
3. Implement zero-touch automation to replace manual, redundant tasks
http://pubads.g.doubleclick.net/gampad/clk?id=51271111&iu=/4140/ostg.clktrk
_______________________________________________
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel

Reply via email to