[lxc-devel] [PATCH 1/4] Automatic mounts: improvements for /proc and /sys

Christian Seiler christian at iwakd.de
Tue Sep 24 20:45:06 UTC 2013


Improve lxc.mount.auto code: allow the user to specify whether to mount
certain things read-only or read-write. Also make the code much more
easily extensible for the future.

Signed-off-by: Christian Seiler <christian at iwakd.de>
---
 src/lxc/conf.c    |  144 +++++++++++++++++++++++++----------------------------
 src/lxc/conf.h    |   21 ++++++--
 src/lxc/confile.c |   25 ++++++++--
 3 files changed, 105 insertions(+), 85 deletions(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index e933c9a..dd69a80 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -743,85 +743,85 @@ int pin_rootfs(const char *rootfs)
 
 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
+	size_t i;
+	static struct {
+		int match_mask;
+		int match_flag;
+		const char *source;
+		const char *destination;
+		const char *fstype;
+		unsigned long flags;
+		const char *options;
+	} default_mounts[] = {
+		/* Read-only bind-mounting... In older kernels, doing that required
+		 * to do one MS_BIND mount and then MS_REMOUNT|MS_RDONLY the same
+		 * one. According to mount(2) manpage, MS_BIND honors MS_RDONLY from
+		 * kernel 2.6.26 onwards. However, this apparently does not work on
+		 * kernel 3.8. Unfortunately, on that very same kernel, doing the
+		 * same trick as above doesn't seem to work either, there one needs
+		 * to ALSO specify MS_BIND for the remount, otherwise the entire
+		 * fs is remounted read-only or the mount fails because it's busy...
+		 * MS_REMOUNT|MS_BIND|MS_RDONLY seems to work for kernels as low as
+		 * 2.6.32...
 		 */
-		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;
-		}
+		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, "proc",                  "%r/proc",               "proc",  MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL },
+		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, "%r/proc/sys",           "%r/proc/sys",           NULL,    MS_BIND,                      NULL },
+		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, NULL,                    "%r/proc/sys",           NULL,    MS_REMOUNT|MS_BIND|MS_RDONLY, NULL },
+		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, "%r/proc/sysrq-trigger", "%r/proc/sysrq-trigger", NULL,    MS_BIND,                      NULL },
+		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, NULL,                    "%r/proc/sysrq-trigger", NULL,    MS_REMOUNT|MS_BIND|MS_RDONLY, NULL },
+		{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW,    "proc",                  "%r/proc",               "proc",  MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL },
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                 "%r/sys",                "sysfs", 0,                            NULL },
+		{ LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                 "%r/sys",                "sysfs", MS_RDONLY,                    NULL },
+		{ 0,                  0,                   NULL,                    NULL,                    NULL,    0,                            NULL }
+	};
 
-		r = mount("sysfs", path, "sysfs", MS_RDONLY, NULL);
-		if (r < 0) {
-			SYSERROR("error mounting /sys");
-			goto cleanup;
+	for (i = 0; default_mounts[i].match_mask; i++) {
+		if ((flags & default_mounts[i].match_mask) == default_mounts[i].match_flag) {
+			char *source = NULL;
+			char *destination = NULL;
+			int saved_errno;
+
+			if (default_mounts[i].source) {
+				/* will act like strdup if %r is not present */
+				source = lxc_string_replace("%r", conf->rootfs.mount, default_mounts[i].source);
+				if (!source) {
+					SYSERROR("memory allocation error");
+					return -1;
+				}
+			}
+			if (default_mounts[i].destination) {
+				/* will act like strdup if %r is not present */
+				destination = lxc_string_replace("%r", conf->rootfs.mount, default_mounts[i].destination);
+				if (!destination) {
+					saved_errno = errno;
+					SYSERROR("memory allocation error");
+					free(source);
+					errno = saved_errno;
+					return -1;
+				}
+			}
+			r = mount(source, destination, default_mounts[i].fstype, default_mounts[i].flags, default_mounts[i].options);
+			saved_errno = errno;
+			free(source);
+			free(destination);
+			if (r < 0) {
+				SYSERROR("error mounting %s", default_mounts[i].destination);
+				errno = saved_errno;
+				return -1;
+			}
 		}
-
-		free(path);
-		path = NULL;
 	}
 
-	if (flags & LXC_AUTO_CGROUP) {
+	if (flags & LXC_AUTO_CGROUP_MASK) {
 		r = lxc_setup_mount_cgroup(conf->rootfs.mount, cgroup_info);
 		if (r < 0) {
 			SYSERROR("error mounting /sys/fs/cgroup");
-			goto cleanup;
+			return -1;
 		}
 	}
 
-	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)
@@ -3077,7 +3077,7 @@ 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) {
+	if (lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & ~LXC_AUTO_CGROUP_MASK, cgroup_info) < 0) {
 		ERROR("failed to setup the automatic mounts for '%s'", name);
 		return -1;
 	}
@@ -3096,7 +3096,7 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf, const char *lxcpath,
 	 * 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) {
+	if (lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & LXC_AUTO_CGROUP_MASK, cgroup_info) < 0) {
 		ERROR("failed to setup the automatic mounts for '%s'", name);
 		return -1;
 	}
@@ -3117,14 +3117,6 @@ 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 d99bdfe..01bd109 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -225,10 +225,23 @@ 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 */
+	LXC_AUTO_PROC_RW              = 0x001,   /* /proc read-write */
+	LXC_AUTO_PROC_MIXED           = 0x002,   /* /proc/sys and /proc/sysrq-trigger read-only */
+	LXC_AUTO_PROC_MASK            = 0x003,
+
+	LXC_AUTO_SYS_RW               = 0x004,   /* /sys */
+	LXC_AUTO_SYS_RO               = 0x008,   /* /sys read-only */
+	LXC_AUTO_SYS_MASK             = 0x00C,
+
+	LXC_AUTO_CGROUP_RO            = 0x010,   /* /sys/fs/cgroup (partial mount, read-only) */
+	LXC_AUTO_CGROUP_RW            = 0x020,   /* /sys/fs/cgroup (partial mount, read-write) */
+	LXC_AUTO_CGROUP_MIXED         = 0x030,   /* /sys/fs/cgroup (partial mount, paths r/o, cgroup r/w) */
+	LXC_AUTO_CGROUP_FULL_RO       = 0x040,   /* /sys/fs/cgroup (full mount, read-only) */
+	LXC_AUTO_CGROUP_FULL_RW       = 0x050,   /* /sys/fs/cgroup (full mount, read-write) */
+	LXC_AUTO_CGROUP_FULL_MIXED    = 0x060,   /* /sys/fs/cgroup (full mount, parent r/o, own r/w) */
+	LXC_AUTO_CGROUP_MASK          = 0x070,
+
+	LXC_AUTO_ALL_MASK             = 0x07F,   /* all known settings */
 };
 
 /*
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index b378c3a..04b8e57 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -1239,11 +1239,25 @@ 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 },
+	static struct { const char *token; int mask; int flag; } allowed_auto_mounts[] = {
+		{ "proc",               LXC_AUTO_PROC_MASK,      LXC_AUTO_PROC_MIXED        },
+		{ "proc:mixed",         LXC_AUTO_PROC_MASK,      LXC_AUTO_PROC_MIXED        },
+		{ "proc:rw",            LXC_AUTO_PROC_MASK,      LXC_AUTO_PROC_RW           },
+		{ "sys",                LXC_AUTO_SYS_MASK,       LXC_AUTO_SYS_RO            },
+		{ "sys:ro",             LXC_AUTO_SYS_MASK,       LXC_AUTO_SYS_RO            },
+		{ "sys:rw",             LXC_AUTO_SYS_MASK,       LXC_AUTO_SYS_RW            },
+		{ "cgroup",             LXC_AUTO_CGROUP_MASK,    LXC_AUTO_CGROUP_MIXED      },
+		{ "cgroup:mixed",       LXC_AUTO_CGROUP_MASK,    LXC_AUTO_CGROUP_MIXED      },
+		{ "cgroup:ro",          LXC_AUTO_CGROUP_MASK,    LXC_AUTO_CGROUP_RO         },
+		{ "cgroup:rw",          LXC_AUTO_CGROUP_MASK,    LXC_AUTO_CGROUP_RW         },
+		{ "cgroup-full",        LXC_AUTO_CGROUP_MASK,    LXC_AUTO_CGROUP_FULL_MIXED },
+		{ "cgroup-full:mixed",  LXC_AUTO_CGROUP_MASK,    LXC_AUTO_CGROUP_FULL_MIXED },
+		{ "cgroup-full:ro",     LXC_AUTO_CGROUP_MASK,    LXC_AUTO_CGROUP_FULL_RO    },
+		{ "cgroup-full:rw",     LXC_AUTO_CGROUP_MASK,    LXC_AUTO_CGROUP_FULL_RW    },
+		/* NB: For adding anything that ist just a single on/off, but has
+		 *     no options: keep mask and flag identical and just define the
+		 *     enum value as an unused bit so far
+		 */
 		{ NULL, 0 }
 	};
 	int i;
@@ -1275,6 +1289,7 @@ static int config_mount_auto(const char *key, const char *value,
 			break;
 		}
 
+		lxc_conf->auto_mounts &= ~allowed_auto_mounts[i].mask;
 		lxc_conf->auto_mounts |= allowed_auto_mounts[i].flag;
         }
 
-- 
1.7.10.4





More information about the lxc-devel mailing list