Commit 368bbc02 by Christian Seiler Committed by Serge Hallyn

Support for automatic mounting of filesystems

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: 's avatarChristian Seiler <christian@iwakd.de> Signed-off-by: 's avatarSerge Hallyn <serge.hallyn@ubuntu.com>
parent aae1f3c4
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
#include "lxc.h" /* for lxc_cgroup_set() */ #include "lxc.h" /* for lxc_cgroup_set() */
#include "caps.h" /* for lxc_caps_last_cap() */ #include "caps.h" /* for lxc_caps_last_cap() */
#include "bdev.h" #include "bdev.h"
#include "cgroup.h"
#if HAVE_APPARMOR #if HAVE_APPARMOR
#include <apparmor.h> #include <apparmor.h>
...@@ -707,6 +708,89 @@ int pin_rootfs(const char *rootfs) ...@@ -707,6 +708,89 @@ int pin_rootfs(const char *rootfs)
return fd; 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) static int mount_rootfs(const char *rootfs, const char *target)
{ {
char absrootfs[MAXPATHLEN]; char absrootfs[MAXPATHLEN];
...@@ -2878,7 +2962,7 @@ int uid_shift_ttys(int pid, struct lxc_conf *conf) ...@@ -2878,7 +2962,7 @@ int uid_shift_ttys(int pid, struct lxc_conf *conf)
return 0; 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 */ #if HAVE_APPARMOR /* || HAVE_SMACK || HAVE_SELINUX */
int mounted; int mounted;
...@@ -2911,6 +2995,14 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf, const char *lxcpath) ...@@ -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)) { if (setup_mount(&lxc_conf->rootfs, lxc_conf->fstab, name)) {
ERROR("failed to setup the mounts for '%s'", name); ERROR("failed to setup the mounts for '%s'", name);
return -1; return -1;
...@@ -2921,6 +3013,15 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf, const char *lxcpath) ...@@ -2921,6 +3013,15 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf, const char *lxcpath)
return -1; 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)) { if (run_lxc_hooks(name, "mount", lxc_conf, lxcpath, NULL)) {
ERROR("failed to run mount hooks for container '%s'.", name); ERROR("failed to run mount hooks for container '%s'.", name);
return -1; return -1;
...@@ -2937,6 +3038,14 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf, const char *lxcpath) ...@@ -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)) { 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); ERROR("failed to setup the console for '%s'", name);
return -1; return -1;
......
...@@ -222,6 +222,16 @@ struct lxc_rootfs { ...@@ -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 * Defines the global container configuration
* @rootfs : root directory to run the container * @rootfs : root directory to run the container
* @pivotdir : pivotdir path, if not set default will be used * @pivotdir : pivotdir path, if not set default will be used
...@@ -265,6 +275,7 @@ struct lxc_conf { ...@@ -265,6 +275,7 @@ struct lxc_conf {
struct lxc_list network; struct lxc_list network;
struct saved_nic *saved_nics; struct saved_nic *saved_nics;
int num_savednics; int num_savednics;
int auto_mounts;
struct lxc_list mount_list; struct lxc_list mount_list;
struct lxc_list caps; struct lxc_list caps;
struct lxc_list keepcaps; struct lxc_list keepcaps;
...@@ -336,8 +347,9 @@ extern int uid_shift_ttys(int pid, struct lxc_conf *conf); ...@@ -336,8 +347,9 @@ extern int uid_shift_ttys(int pid, struct lxc_conf *conf);
* Configure the container from inside * Configure the container from inside
*/ */
struct cgroup_process_info;
extern int lxc_setup(const char *name, struct lxc_conf *lxc_conf, 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); extern void lxc_rename_phys_nics_on_shutdown(struct lxc_conf *conf);
#endif #endif
...@@ -1235,11 +1235,60 @@ static int config_fstab(const char *key, const char *value, ...@@ -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); 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, static int config_mount(const char *key, const char *value,
struct lxc_conf *lxc_conf) struct lxc_conf *lxc_conf)
{ {
char *fstab_token = "lxc.mount"; char *fstab_token = "lxc.mount";
char *token = "lxc.mount.entry"; char *token = "lxc.mount.entry";
char *auto_token = "lxc.mount.auto";
char *subkey; char *subkey;
char *mntelem; char *mntelem;
struct lxc_list *mntlist; struct lxc_list *mntlist;
...@@ -1247,6 +1296,9 @@ static int config_mount(const char *key, const char *value, ...@@ -1247,6 +1296,9 @@ static int config_mount(const char *key, const char *value,
subkey = strstr(key, token); subkey = strstr(key, token);
if (!subkey) { if (!subkey) {
subkey = strstr(key, auto_token);
if (!subkey) {
subkey = strstr(key, fstab_token); subkey = strstr(key, fstab_token);
if (!subkey) if (!subkey)
...@@ -1255,6 +1307,9 @@ static int config_mount(const char *key, const char *value, ...@@ -1255,6 +1307,9 @@ static int config_mount(const char *key, const char *value,
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)) if (!strlen(subkey))
return -1; return -1;
......
...@@ -525,7 +525,7 @@ static int do_start(void *data) ...@@ -525,7 +525,7 @@ static int do_start(void *data)
#endif #endif
/* Setup the container, ip, names, utsname, ... */ /* 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"); ERROR("failed to setup the container");
goto out_warn_father; goto out_warn_father;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment