#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>
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];
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;
}
}
+ /* 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;
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;
}
}
+ /* 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;
char *pivot;
};
+/*
+ * 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
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;
* 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
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;
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))