user namespace doesn't allow to create devices in
uninit userns. We should create devices on host side.
We first mount tmpfs on dev directroy under state dir
of container. then create devices under this dev dir.
Finally in container, mount the dev directroy created
on host to the /dev/ directroy of container.
Signed-off-by: Gao feng <gaofeng(a)cn.fujitsu.com>
---
src/lxc/lxc_container.c | 86 ++++++++++++++++------------------------
src/lxc/lxc_controller.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 134 insertions(+), 52 deletions(-)
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index 4b782bb..958e20d 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -683,7 +683,7 @@ err:
}
-static int lxcContainerMountBasicFS(char *sec_mount_options)
+static int lxcContainerMountBasicFS(void)
{
const struct {
const char *src;
@@ -709,9 +709,8 @@ static int lxcContainerMountBasicFS(char *sec_mount_options)
#endif
};
int i, rc = -1;
- char *opts = NULL;
- VIR_DEBUG("Mounting basic filesystems sec_mount_options=%s",
sec_mount_options);
+ VIR_DEBUG("Mounting basic filesystems");
for (i = 0; i < ARRAY_CARDINALITY(mnts); i++) {
const char *srcpath = NULL;
@@ -750,31 +749,10 @@ static int lxcContainerMountBasicFS(char *sec_mount_options)
}
}
- /*
- * tmpfs is limited to 64kb, since we only have device nodes in there
- * and don't want to DOS the entire OS RAM usage
- */
-
- if (virAsprintf(&opts,
- "mode=755,size=65536%s", sec_mount_options) < 0) {
- virReportOOMError();
- goto cleanup;
- }
-
- VIR_DEBUG("Mount devfs on /dev type=tmpfs flags=%x, opts=%s",
- MS_NOSUID, opts);
- if (mount("devfs", "/dev", "tmpfs", MS_NOSUID, opts)
< 0) {
- virReportSystemError(errno,
- _("Failed to mount %s on %s type %s (%s)"),
- "devfs", "/dev", "tmpfs",
opts);
- goto cleanup;
- }
-
rc = 0;
cleanup:
VIR_DEBUG("rc=%d", rc);
- VIR_FREE(opts);
return rc;
}
@@ -811,6 +789,30 @@ static int lxcContainerMountProcFuse(virDomainDefPtr def
ATTRIBUTE_UNUSED,
}
#endif
+static int lxcContainerMountFSDev(virDomainDefPtr def,
+ const char *stateDir)
+{
+ int ret;
+ char *path = NULL;
+
+ VIR_DEBUG("Mount /dev/ stateDir=%s", stateDir);
+
+ if ((ret = virAsprintf(&path, "/.oldroot/%s/%s.dev",
+ stateDir, def->name)) < 0)
+ return ret;
+
+ VIR_DEBUG("Tring to move %s to /dev", path);
+
+ if ((ret = mount(path, "/dev", NULL, MS_MOVE, NULL)) < 0) {
+ virReportSystemError(errno,
+ _("Failed to mount %s on /dev"),
+ path);
+ }
+
+ VIR_FREE(path);
+ return ret;
+}
+
static int lxcContainerMountFSDevPTS(virDomainDefPtr def,
const char *stateDir)
{
@@ -847,22 +849,10 @@ cleanup:
return ret;
}
-static int lxcContainerPopulateDevices(char **ttyPaths, size_t nttyPaths)
+static int lxcContainerSetupDevices(char **ttyPaths, size_t nttyPaths)
{
size_t i;
const struct {
- int maj;
- int min;
- mode_t mode;
- const char *path;
- } devs[] = {
- { LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_NULL, 0666, "/dev/null" },
- { LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_ZERO, 0666, "/dev/zero" },
- { LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_FULL, 0666, "/dev/full" },
- { LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_RANDOM, 0666, "/dev/random" },
- { LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_URANDOM, 0666, "/dev/urandom" },
- };
- const struct {
const char *src;
const char *dst;
} links[] = {
@@ -872,18 +862,6 @@ static int lxcContainerPopulateDevices(char **ttyPaths, size_t
nttyPaths)
{ "/proc/self/fd", "/dev/fd" },
};
- /* Populate /dev/ with a few important bits */
- for (i = 0; i < ARRAY_CARDINALITY(devs); i++) {
- dev_t dev = makedev(devs[i].maj, devs[i].min);
- if (mknod(devs[i].path, S_IFCHR, dev) < 0 ||
- chmod(devs[i].path, devs[i].mode)) {
- virReportSystemError(errno,
- _("Failed to make device %s"),
- devs[i].path);
- return -1;
- }
- }
-
for (i = 0; i < ARRAY_CARDINALITY(links); i++) {
if (symlink(links[i].src, links[i].dst) < 0) {
virReportSystemError(errno,
@@ -1802,7 +1780,7 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef,
goto cleanup;
/* Mounts the core /proc, /sys, etc filesystems */
- if (lxcContainerMountBasicFS(sec_mount_options) < 0)
+ if (lxcContainerMountBasicFS() < 0)
goto cleanup;
/* Mounts /proc/meminfo etc sysinfo */
@@ -1814,12 +1792,16 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef,
if (virCgroupIsolateMount(cgroup, "/.oldroot/", sec_mount_options) < 0)
goto cleanup;
+ /* Mounts /dev */
+ if (lxcContainerMountFSDev(vmDef, stateDir) < 0)
+ goto cleanup;
+
/* Mounts /dev/pts */
if (lxcContainerMountFSDevPTS(vmDef, stateDir) < 0)
goto cleanup;
- /* Populates device nodes in /dev/ */
- if (lxcContainerPopulateDevices(ttyPaths, nttyPaths) < 0)
+ /* Setup device nodes in /dev/ */
+ if (lxcContainerSetupDevices(ttyPaths, nttyPaths) < 0)
goto cleanup;
/* Sets up any non-root mounts from guest config */
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index ef41efb..75c7a85 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -1192,6 +1192,103 @@ cleanup:
return ret;
}
+static int virLXCControllerSetupDev(virLXCControllerPtr ctrl)
+{
+ char *mount_options = NULL;
+ char *opts = NULL;
+ char *dev = NULL;
+ int ret = -1;
+
+ VIR_DEBUG("Setting up /dev/ for container");
+
+ mount_options = virSecurityManagerGetMountOptions(ctrl->securityManager,
+ ctrl->def);
+
+ if (virAsprintf(&dev, "/%s/%s.dev",
+ LXC_STATE_DIR, ctrl->def->name) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (virFileMakePath(dev) < 0) {
+ virReportSystemError(errno,
+ _("Failed to make path %s"), dev);
+ goto cleanup;
+ }
+
+ /*
+ * tmpfs is limited to 64kb, since we only have device nodes in there
+ * and don't want to DOS the entire OS RAM usage
+ */
+
+ if (virAsprintf(&opts,
+ "mode=755,size=65536%s", mount_options) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ VIR_DEBUG("Mount devfs on %s type=tmpfs flags=%x, opts=%s",
+ dev, MS_NOSUID, opts);
+ if (mount("devfs", dev, "tmpfs", MS_NOSUID, opts) < 0) {
+ virReportSystemError(errno,
+ _("Failed to mount devfs on %s type %s (%s)"),
+ dev, "tmpfs", opts);
+ goto cleanup;
+ }
+
+ ret = 0;
+cleanup:
+ VIR_FREE(opts);
+ VIR_FREE(mount_options);
+ VIR_FREE(dev);
+ return ret;
+}
+
+static int virLXCControllerPopulateDevices(virLXCControllerPtr ctrl)
+{
+ size_t i;
+ int ret = -1;
+ char *path = NULL;
+ const struct {
+ int maj;
+ int min;
+ mode_t mode;
+ const char *path;
+ } devs[] = {
+ { LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_NULL, 0666, "/null" },
+ { LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_ZERO, 0666, "/zero" },
+ { LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_FULL, 0666, "/full" },
+ { LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_RANDOM, 0666, "/random" },
+ { LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_URANDOM, 0666, "/urandom" },
+ };
+
+ if (virLXCControllerSetupDev(ctrl) < 0)
+ goto cleanup;
+
+ /* Populate /dev/ with a few important bits */
+ for (i = 0; i < ARRAY_CARDINALITY(devs); i++) {
+ if (virAsprintf(&path, "/%s/%s.dev/%s",
+ LXC_STATE_DIR, ctrl->def->name, devs[i].path) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ dev_t dev = makedev(devs[i].maj, devs[i].min);
+ if (mknod(path, S_IFCHR, dev) < 0 ||
+ chmod(path, devs[i].mode)) {
+ virReportSystemError(errno,
+ _("Failed to make device %s"),
+ path);
+ goto cleanup;
+ }
+ VIR_FREE(path);
+ }
+
+ ret = 0;
+cleanup:
+ VIR_FREE(path);
+ return ret;
+}
/**
@@ -1594,6 +1691,9 @@ virLXCControllerRun(virLXCControllerPtr ctrl)
if (virLXCControllerSetupDevPTS(ctrl) < 0)
goto cleanup;
+ if (virLXCControllerPopulateDevices(ctrl) < 0)
+ goto cleanup;
+
if (virLXCControllerSetupFuse(ctrl) < 0)
goto cleanup;
--
1.8.1.4