[lxc-devel] [PATCH 4/4] Support for automatic mounting of filesystems
Christian Seiler
christian at iwakd.de
Wed Sep 11 23:44:44 UTC 2013
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 <christian at 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
More information about the lxc-devel
mailing list