[libvirt] [PATCH RESEND 0/7] LXC: enhance user namespace support for adding the disk and host devices for libvirt lxc

Libvirt lxc has supported user namespace since commit c34107dfd3a25232255e6d6f559b1306ef99bb3b,but for the disk devices and hostdevs, libvirt lxc still creates these device nodes in container. this will fail when container enables user namespace, since user namespace is disallowed to create device node. In order to reslove this problem, we should create device nodes on host side for container,and change the owner of these nodes to the root user of container. Gao feng (7): LXC: Setup disks for container on host side LXC: controller: change the owner of disk to the root of container LXC: Move virLXCControllerChown to lxc_container.c LXC: Change the owner of live attached disk device LXC: Create host devices for container on host side LXC: Change the owner of host devices to the root of container LXC: Change the owner of live attached host devices src/lxc/lxc_container.c | 382 +++------------------------------------- src/lxc/lxc_container.h | 2 + src/lxc/lxc_controller.c | 450 ++++++++++++++++++++++++++++++++++++++++++++--- src/lxc/lxc_driver.c | 13 ++ 4 files changed, 460 insertions(+), 387 deletions(-) -- 1.8.3.1

Since mknod in container is forbidden, we should setup disks on host side. Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/lxc/lxc_container.c | 98 ------------------------------------------------ src/lxc/lxc_controller.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 98 deletions(-) diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index fcd9b74..caad02b 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -1367,100 +1367,6 @@ static int lxcContainerMountAllFS(virDomainDefPtr vmDef, } -static int lxcContainerSetupDisk(virDomainDefPtr vmDef, - virDomainDiskDefPtr def, - virSecurityManagerPtr securityDriver) -{ - char *src = NULL; - char *dst = NULL; - int ret = -1; - struct stat sb; - mode_t mode; - char *tmpsrc = def->src; - - if (def->type != VIR_DOMAIN_DISK_TYPE_BLOCK) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Can't setup disk for non-block device")); - goto cleanup; - } - if (def->src == NULL) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Can't setup disk without media")); - goto cleanup; - } - - if (virAsprintf(&src, "/.oldroot/%s", def->src) < 0) - goto cleanup; - - if (virAsprintf(&dst, "/dev/%s", def->dst) < 0) - goto cleanup; - - if (stat(src, &sb) < 0) { - virReportSystemError(errno, - _("Unable to access %s"), def->src); - goto cleanup; - } - - if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Disk source %s must be a character/block device"), - def->src); - goto cleanup; - } - - mode = 0700; - if (S_ISCHR(sb.st_mode)) - mode |= S_IFCHR; - else - mode |= S_IFBLK; - - /* Yes, the device name we're creating may not - * actually correspond to the major:minor number - * we're using, but we've no other option at this - * time. Just have to hope that containerized apps - * don't get upset that the major:minor is different - * to that normally implied by the device name - */ - VIR_DEBUG("Creating dev %s (%d,%d) from %s", - dst, major(sb.st_rdev), minor(sb.st_rdev), src); - if (mknod(dst, mode, sb.st_rdev) < 0) { - virReportSystemError(errno, - _("Unable to create device %s"), - dst); - goto cleanup; - } - /* Labelling normally operates on src, but we need - * to actally label the dst here, so hack the config */ - def->src = dst; - if (virSecurityManagerSetImageLabel(securityDriver, vmDef, def) < 0) - goto cleanup; - - ret = 0; - -cleanup: - def->src = tmpsrc; - VIR_FREE(src); - VIR_FREE(dst); - return ret; -} - -static int lxcContainerSetupAllDisks(virDomainDefPtr vmDef, - virSecurityManagerPtr securityDriver) -{ - size_t i; - VIR_DEBUG("Setting up disks"); - - for (i = 0; i < vmDef->ndisks; i++) { - if (lxcContainerSetupDisk(vmDef, vmDef->disks[i], - securityDriver) < 0) - return -1; - } - - VIR_DEBUG("Setup all disks"); - return 0; -} - - static int lxcContainerSetupHostdevSubsysUSB(virDomainDefPtr vmDef, virDomainHostdevDefPtr def, virSecurityManagerPtr securityDriver) @@ -1837,10 +1743,6 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef, if (lxcContainerMountAllFS(vmDef, sec_mount_options) < 0) goto cleanup; - /* Sets up any extra disks from guest config */ - if (lxcContainerSetupAllDisks(vmDef, securityDriver) < 0) - goto cleanup; - /* Sets up any extra host devices from guest config */ if (lxcContainerSetupAllHostdevs(vmDef, securityDriver) < 0) goto cleanup; diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 3f3d93b..e9d2848 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -1309,6 +1309,97 @@ cleanup: } +static int virLXCControllerSetupDisk(virLXCControllerPtr ctrl, + virDomainDiskDefPtr def, + virSecurityManagerPtr securityDriver) +{ + char *dst = NULL; + int ret = -1; + struct stat sb; + mode_t mode; + char *tmpsrc = def->src; + + if (def->type != VIR_DOMAIN_DISK_TYPE_BLOCK) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Can't setup disk for non-block device")); + goto cleanup; + } + if (def->src == NULL) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Can't setup disk without media")); + goto cleanup; + } + + if (virAsprintf(&dst, "/%s/%s.dev/%s", + LXC_STATE_DIR, ctrl->def->name, def->dst) < 0) + goto cleanup; + + if (stat(def->src, &sb) < 0) { + virReportSystemError(errno, + _("Unable to access %s"), def->src); + goto cleanup; + } + + if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Disk source %s must be a character/block device"), + def->src); + goto cleanup; + } + + mode = 0700; + if (S_ISCHR(sb.st_mode)) + mode |= S_IFCHR; + else + mode |= S_IFBLK; + + /* Yes, the device name we're creating may not + * actually correspond to the major:minor number + * we're using, but we've no other option at this + * time. Just have to hope that containerized apps + * don't get upset that the major:minor is different + * to that normally implied by the device name + */ + VIR_DEBUG("Creating dev %s (%d,%d) from %s", + dst, major(sb.st_rdev), minor(sb.st_rdev), def->src); + if (mknod(dst, mode, sb.st_rdev) < 0) { + virReportSystemError(errno, + _("Unable to create device %s"), + dst); + goto cleanup; + } + + /* Labelling normally operates on src, but we need + * to actally label the dst here, so hack the config */ + def->src = dst; + if (virSecurityManagerSetImageLabel(securityDriver, ctrl->def, def) < 0) + goto cleanup; + + ret = 0; + +cleanup: + def->src = tmpsrc; + VIR_FREE(dst); + return ret; +} + +static int virLXCControllerSetupAllDisks(virLXCControllerPtr ctrl) +{ + size_t i; + VIR_DEBUG("Setting up disks"); + + for (i = 0; i < ctrl->def->ndisks; i++) { + if (virLXCControllerSetupDisk(ctrl, ctrl->def->disks[i], + ctrl->securityManager) < 0) + return -1; + } + + VIR_DEBUG("Setup all disks"); + return 0; +} + + + /** * virLXCControllerMoveInterfaces * @nveths: number of interfaces @@ -1724,6 +1815,9 @@ virLXCControllerRun(virLXCControllerPtr ctrl) if (virLXCControllerPopulateDevices(ctrl) < 0) goto cleanup; + if (virLXCControllerSetupAllDisks(ctrl) < 0) + goto cleanup; + if (virLXCControllerSetupFuse(ctrl) < 0) goto cleanup; -- 1.8.3.1

On Tue, Jul 16, 2013 at 10:00:00AM +0800, Gao feng wrote:
Since mknod in container is forbidden, we should setup disks on host side.
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/lxc/lxc_container.c | 98 ------------------------------------------------ src/lxc/lxc_controller.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 98 deletions(-)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

These disk devices are created for container, the owner should be the root user of container. Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/lxc/lxc_controller.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index e9d2848..38b632e 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -1369,6 +1369,9 @@ static int virLXCControllerSetupDisk(virLXCControllerPtr ctrl, goto cleanup; } + if (virLXCControllerChown(ctrl, dst) < 0) + goto cleanup; + /* Labelling normally operates on src, but we need * to actally label the dst here, so hack the config */ def->src = dst; -- 1.8.3.1

On Tue, Jul 16, 2013 at 10:00:01AM +0800, Gao feng wrote:
These disk devices are created for container, the owner should be the root user of container.
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/lxc/lxc_controller.c | 3 +++ 1 file changed, 3 insertions(+)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

lxc driver will use this function to change the owner of hot added devices. Move virLXCControllerChown to lxc_container.c and Rename it to lxcContainerChown. Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/lxc/lxc_container.c | 21 +++++++++++++++++++++ src/lxc/lxc_container.h | 2 ++ src/lxc/lxc_controller.c | 33 ++++++--------------------------- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index caad02b..6bc259b 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -2116,3 +2116,24 @@ int lxcContainerAvailable(int features) VIR_DEBUG("container support is enabled"); return 0; } + +int lxcContainerChown(virDomainDefPtr def, const char *path) +{ + uid_t uid; + gid_t gid; + + if (!def->idmap.uidmap) + return 0; + + uid = def->idmap.uidmap[0].target; + gid = def->idmap.gidmap[0].target; + + if (chown(path, uid, gid) < 0) { + virReportSystemError(errno, + _("Failed to change owner of %s to %u:%u"), + path, uid, gid); + return -1; + } + + return 0; +} diff --git a/src/lxc/lxc_container.h b/src/lxc/lxc_container.h index 6f270d7..0e3b591 100644 --- a/src/lxc/lxc_container.h +++ b/src/lxc/lxc_container.h @@ -67,4 +67,6 @@ int lxcContainerSetupHostdevCapsMakePath(const char *dev); virArch lxcContainerGetAlt32bitArch(virArch arch); +int lxcContainerChown(virDomainDefPtr def, const char *path); + #endif /* LXC_CONTAINER_H */ diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 38b632e..4907af4 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -1113,27 +1113,6 @@ cleanup2: return rc; } -static int -virLXCControllerChown(virLXCControllerPtr ctrl, char *path) -{ - uid_t uid; - gid_t gid; - - if (!ctrl->def->idmap.uidmap) - return 0; - - uid = ctrl->def->idmap.uidmap[0].target; - gid = ctrl->def->idmap.gidmap[0].target; - - if (chown(path, uid, gid) < 0) { - virReportSystemError(errno, - _("Failed to change owner of %s to %u:%u"), - path, uid, gid); - return -1; - } - - return 0; -} static int virLXCControllerSetupUsernsMap(virDomainIdMapEntryPtr map, @@ -1248,7 +1227,7 @@ static int virLXCControllerSetupDev(virLXCControllerPtr ctrl) goto cleanup; } - if (virLXCControllerChown(ctrl, dev) < 0) + if (lxcContainerChown(ctrl->def, dev) < 0) goto cleanup; ret = 0; @@ -1296,7 +1275,7 @@ static int virLXCControllerPopulateDevices(virLXCControllerPtr ctrl) goto cleanup; } - if (virLXCControllerChown(ctrl, path) < 0) + if (lxcContainerChown(ctrl->def, path) < 0) goto cleanup; VIR_FREE(path); @@ -1369,7 +1348,7 @@ static int virLXCControllerSetupDisk(virLXCControllerPtr ctrl, goto cleanup; } - if (virLXCControllerChown(ctrl, dst) < 0) + if (lxcContainerChown(ctrl->def, dst) < 0) goto cleanup; /* Labelling normally operates on src, but we need @@ -1627,8 +1606,8 @@ virLXCControllerSetupDevPTS(virLXCControllerPtr ctrl) goto cleanup; } - if ((virLXCControllerChown(ctrl, ctrl->devptmx) < 0) || - (virLXCControllerChown(ctrl, devpts) < 0)) + if ((lxcContainerChown(ctrl->def, ctrl->devptmx) < 0) || + (lxcContainerChown(ctrl->def, devpts) < 0)) goto cleanup; ret = 0; @@ -1666,7 +1645,7 @@ virLXCControllerSetupConsoles(virLXCControllerPtr ctrl, } /* Change the owner of tty device to the root user of container */ - if (virLXCControllerChown(ctrl, ttyHostPath) < 0) + if (lxcContainerChown(ctrl->def, ttyHostPath) < 0) goto cleanup; VIR_FREE(ttyHostPath); -- 1.8.3.1

On Tue, Jul 16, 2013 at 10:00:02AM +0800, Gao feng wrote:
lxc driver will use this function to change the owner of hot added devices.
Move virLXCControllerChown to lxc_container.c and Rename it to lxcContainerChown.
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/lxc/lxc_container.c | 21 +++++++++++++++++++++ src/lxc/lxc_container.h | 2 ++ src/lxc/lxc_controller.c | 33 ++++++--------------------------- 3 files changed, 29 insertions(+), 27 deletions(-)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

The owner of this disk device should be the root user of container. Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/lxc/lxc_driver.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 1279edf..bd92135 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -3258,6 +3258,10 @@ lxcDomainAttachDeviceDiskLive(virLXCDriverPtr driver, dst); goto cleanup; } + + if (lxcContainerChown(vm->def, dst) < 0) + goto cleanup; + created = true; /* Labelling normally operates on src, but we need -- 1.8.3.1

On Tue, Jul 16, 2013 at 10:00:03AM +0800, Gao feng wrote:
The owner of this disk device should be the root user of container.
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/lxc/lxc_driver.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 1279edf..bd92135 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -3258,6 +3258,10 @@ lxcDomainAttachDeviceDiskLive(virLXCDriverPtr driver, dst); goto cleanup; } + + if (lxcContainerChown(vm->def, dst) < 0) + goto cleanup; + created = true;
/* Labelling normally operates on src, but we need
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Otherwise the container will fail to start if we enable user namespace, since there is no rights to do mknod in uninit user namespace. Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/lxc/lxc_container.c | 263 --------------------------------------- src/lxc/lxc_controller.c | 313 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 313 insertions(+), 263 deletions(-) diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 6bc259b..955ad41 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -1367,72 +1367,6 @@ static int lxcContainerMountAllFS(virDomainDefPtr vmDef, } -static int lxcContainerSetupHostdevSubsysUSB(virDomainDefPtr vmDef, - virDomainHostdevDefPtr def, - virSecurityManagerPtr securityDriver) -{ - int ret = -1; - char *src = NULL; - char *dstdir = NULL; - char *dstfile = NULL; - struct stat sb; - mode_t mode; - - if (virAsprintf(&dstdir, USB_DEVFS "/%03d", - def->source.subsys.u.usb.bus) < 0) - goto cleanup; - - if (virAsprintf(&dstfile, "%s/%03d", - dstdir, - def->source.subsys.u.usb.device) < 0) - goto cleanup; - - if (virAsprintf(&src, "/.oldroot/%s", dstfile) < 0) - goto cleanup; - - if (stat(src, &sb) < 0) { - virReportSystemError(errno, - _("Unable to access %s"), src); - goto cleanup; - } - - if (!S_ISCHR(sb.st_mode)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("USB source %s was not a character device"), - src); - goto cleanup; - } - - mode = 0700 | S_IFCHR; - - if (virFileMakePath(dstdir) < 0) { - virReportSystemError(errno, - _("Unable to create %s"), dstdir); - goto cleanup; - } - - VIR_DEBUG("Creating dev %s (%d,%d)", - dstfile, major(sb.st_rdev), minor(sb.st_rdev)); - if (mknod(dstfile, mode, sb.st_rdev) < 0) { - virReportSystemError(errno, - _("Unable to create device %s"), - dstfile); - goto cleanup; - } - - if (virSecurityManagerSetHostdevLabel(securityDriver, vmDef, def, NULL) < 0) - goto cleanup; - - ret = 0; - -cleanup: - VIR_FREE(src); - VIR_FREE(dstfile); - VIR_FREE(dstdir); - return ret; -} - - int lxcContainerSetupHostdevCapsMakePath(const char *dev) { int ret = -1; @@ -1459,199 +1393,6 @@ cleanup: } -static int lxcContainerSetupHostdevCapsStorage(virDomainDefPtr vmDef, - virDomainHostdevDefPtr def, - virSecurityManagerPtr securityDriver) -{ - char *src = NULL; - int ret = -1; - struct stat sb; - mode_t mode; - char *dev = def->source.caps.u.storage.block; - - if (dev == NULL) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Missing storage host block path")); - goto cleanup; - } - - if (virAsprintf(&src, "/.oldroot/%s", dev) < 0) - goto cleanup; - - if (stat(src, &sb) < 0) { - virReportSystemError(errno, - _("Unable to access %s"), - src); - goto cleanup; - } - - if (!S_ISBLK(sb.st_mode)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Storage source %s must be a block device"), - dev); - goto cleanup; - } - - if (lxcContainerSetupHostdevCapsMakePath(dev) < 0) { - virReportError(errno, - _("Failed to create directory for device %s"), - dev); - goto cleanup; - } - - mode = 0700 | S_IFBLK; - - VIR_DEBUG("Creating dev %s (%d,%d)", dev, - major(sb.st_rdev), minor(sb.st_rdev)); - if (mknod(dev, mode, sb.st_rdev) < 0) { - virReportSystemError(errno, - _("Unable to create device %s"), - dev); - goto cleanup; - } - - if (virSecurityManagerSetHostdevLabel(securityDriver, vmDef, def, NULL) < 0) - goto cleanup; - - ret = 0; - -cleanup: - VIR_FREE(src); - return ret; -} - - -static int lxcContainerSetupHostdevCapsMisc(virDomainDefPtr vmDef, - virDomainHostdevDefPtr def, - virSecurityManagerPtr securityDriver) -{ - char *src = NULL; - int ret = -1; - struct stat sb; - mode_t mode; - char *dev = def->source.caps.u.misc.chardev; - - if (dev == NULL) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Missing storage host block path")); - goto cleanup; - } - - if (virAsprintf(&src, "/.oldroot/%s", dev) < 0) - goto cleanup; - - if (stat(src, &sb) < 0) { - virReportSystemError(errno, - _("Unable to access %s"), - src); - goto cleanup; - } - - if (!S_ISCHR(sb.st_mode)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Storage source %s must be a character device"), - dev); - goto cleanup; - } - - if (lxcContainerSetupHostdevCapsMakePath(dev) < 0) { - virReportError(errno, - _("Failed to create directory for device %s"), - dev); - goto cleanup; - } - - mode = 0700 | S_IFCHR; - - VIR_DEBUG("Creating dev %s (%d,%d)", dev, - major(sb.st_rdev), minor(sb.st_rdev)); - if (mknod(dev, mode, sb.st_rdev) < 0) { - virReportSystemError(errno, - _("Unable to create device %s"), - dev); - goto cleanup; - } - - if (virSecurityManagerSetHostdevLabel(securityDriver, vmDef, def, NULL) < 0) - goto cleanup; - - ret = 0; - -cleanup: - VIR_FREE(src); - return ret; -} - -static int lxcContainerSetupHostdevSubsys(virDomainDefPtr vmDef, - virDomainHostdevDefPtr def, - virSecurityManagerPtr securityDriver) -{ - switch (def->source.subsys.type) { - case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: - return lxcContainerSetupHostdevSubsysUSB(vmDef, def, securityDriver); - - default: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Unsupported host device mode %s"), - virDomainHostdevSubsysTypeToString(def->source.subsys.type)); - return -1; - } -} - - -static int lxcContainerSetupHostdevCaps(virDomainDefPtr vmDef, - virDomainHostdevDefPtr def, - virSecurityManagerPtr securityDriver) -{ - switch (def->source.subsys.type) { - case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE: - return lxcContainerSetupHostdevCapsStorage(vmDef, def, securityDriver); - - case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC: - return lxcContainerSetupHostdevCapsMisc(vmDef, def, securityDriver); - - case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET: - return 0; // case is handled in virLXCControllerMoveInterfaces - - default: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Unsupported host device mode %s"), - virDomainHostdevCapsTypeToString(def->source.subsys.type)); - return -1; - } -} - - -static int lxcContainerSetupAllHostdevs(virDomainDefPtr vmDef, - virSecurityManagerPtr securityDriver) -{ - size_t i; - VIR_DEBUG("Setting up hostdevs"); - - for (i = 0; i < vmDef->nhostdevs; i++) { - virDomainHostdevDefPtr def = vmDef->hostdevs[i]; - switch (def->mode) { - case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS: - if (lxcContainerSetupHostdevSubsys(vmDef, def, securityDriver) < 0) - return -1; - break; - case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES: - if (lxcContainerSetupHostdevCaps(vmDef, def, securityDriver) < 0) - return -1; - break; - default: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Unsupported host device mode %s"), - virDomainHostdevModeTypeToString(def->mode)); - return -1; - } - } - - VIR_DEBUG("Setup all hostdevs"); - return 0; -} - - /* Got a FS mapped to /, we're going the pivot_root * approach to do a better-chroot-than-chroot * this is based on this thread http://lkml.org/lkml/2008/3/5/29 @@ -1743,10 +1484,6 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef, if (lxcContainerMountAllFS(vmDef, sec_mount_options) < 0) goto cleanup; - /* Sets up any extra host devices from guest config */ - if (lxcContainerSetupAllHostdevs(vmDef, securityDriver) < 0) - goto cleanup; - /* Gets rid of all remaining mounts from host OS, including /.oldroot itself */ if (lxcContainerUnmountSubtree("/.oldroot", true) < 0) goto cleanup; diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 4907af4..dbb053a 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -1288,6 +1288,316 @@ cleanup: } +static int +virLXCControllerSetupHostdevSubsysUSB(virDomainDefPtr vmDef, + virDomainHostdevDefPtr def, + virSecurityManagerPtr securityDriver) +{ + int ret = -1; + char *src = NULL; + char *dstdir = NULL; + char *dstfile = NULL; + char *vroot = NULL; + struct stat sb; + mode_t mode; + + if (virAsprintf(&src, USB_DEVFS "/%03d/%03d", + def->source.subsys.u.usb.bus, + def->source.subsys.u.usb.device) < 0) + goto cleanup; + + if (virAsprintf(&vroot, "/%s/%s.dev/bus/usb/", + LXC_STATE_DIR, vmDef->name) < 0) + goto cleanup; + + if (virAsprintf(&dstdir, "%s/%03d/", vroot, + def->source.subsys.u.usb.bus) < 0) + goto cleanup; + + if (virAsprintf(&dstfile, "%s/%03d", dstdir, + def->source.subsys.u.usb.device) < 0) + goto cleanup; + + if (stat(src, &sb) < 0) { + virReportSystemError(errno, + _("Unable to access %s"), src); + goto cleanup; + } + + if (!S_ISCHR(sb.st_mode)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("USB source %s was not a character device"), + src); + goto cleanup; + } + + mode = 0700 | S_IFCHR; + + if (virFileMakePath(dstdir) < 0) { + virReportSystemError(errno, + _("Unable to create %s"), dstdir); + goto cleanup; + } + + VIR_DEBUG("Creating dev %s (%d,%d)", + dstfile, major(sb.st_rdev), minor(sb.st_rdev)); + if (mknod(dstfile, mode, sb.st_rdev) < 0) { + virReportSystemError(errno, + _("Unable to create device %s"), + dstfile); + goto cleanup; + } + + if (virSecurityManagerSetHostdevLabel(securityDriver, + vmDef, def, vroot) < 0) + goto cleanup; + + ret = 0; + +cleanup: + VIR_FREE(src); + VIR_FREE(dstfile); + VIR_FREE(dstdir); + VIR_FREE(vroot); + return ret; +} + + +static int +virLXCControllerSetupHostdevCapsStorage(virDomainDefPtr vmDef, + virDomainHostdevDefPtr def, + virSecurityManagerPtr securityDriver) +{ + char *dst = NULL; + char *path = NULL; + int len = 0; + int ret = -1; + struct stat sb; + mode_t mode; + char *dev = def->source.caps.u.storage.block; + + if (dev == NULL) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Missing storage host block path")); + goto cleanup; + } + + if (VIR_STRDUP(path, dev) < 0) + goto cleanup; + + while (*(path + len) == '/') + len++; + + if (virAsprintf(&dst, "/%s/%s.dev/%s", + LXC_STATE_DIR, vmDef->name, + strchr(path + len, '/')) < 0) + goto cleanup; + + if (stat(dev, &sb) < 0) { + virReportSystemError(errno, + _("Unable to access %s"), + dev); + goto cleanup; + } + + if (!S_ISBLK(sb.st_mode)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Storage source %s must be a block device"), + dev); + goto cleanup; + } + + if (lxcContainerSetupHostdevCapsMakePath(dst) < 0) { + virReportError(errno, + _("Failed to create directory for device %s"), + dev); + goto cleanup; + } + + mode = 0700 | S_IFBLK; + + VIR_DEBUG("Creating dev %s (%d,%d)", dst, + major(sb.st_rdev), minor(sb.st_rdev)); + if (mknod(dst, mode, sb.st_rdev) < 0) { + virReportSystemError(errno, + _("Unable to create device %s"), + dst); + goto cleanup; + } + + def->source.caps.u.storage.block = dst; + if (virSecurityManagerSetHostdevLabel(securityDriver, vmDef, def, NULL) < 0) + goto cleanup; + + ret = 0; + +cleanup: + def->source.caps.u.storage.block = dev; + VIR_FREE(dst); + VIR_FREE(path); + return ret; +} + + +static int +virLXCControllerSetupHostdevCapsMisc(virDomainDefPtr vmDef, + virDomainHostdevDefPtr def, + virSecurityManagerPtr securityDriver) +{ + char *dst = NULL; + char *path = NULL; + int len = 0; + int ret = -1; + struct stat sb; + mode_t mode; + char *dev = def->source.caps.u.misc.chardev; + + if (dev == NULL) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Missing storage host block path")); + goto cleanup; + } + + if (VIR_STRDUP(path, dev) < 0) + goto cleanup; + + while (*(path + len) == '/') + len++; + + if (virAsprintf(&dst, "/%s/%s.dev/%s", + LXC_STATE_DIR, vmDef->name, + strchr(path + len, '/')) < 0) + goto cleanup; + + if (stat(dev, &sb) < 0) { + virReportSystemError(errno, + _("Unable to access %s"), + dev); + goto cleanup; + } + + if (!S_ISCHR(sb.st_mode)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Storage source %s must be a character device"), + dev); + goto cleanup; + } + + if (lxcContainerSetupHostdevCapsMakePath(dst) < 0) { + virReportError(errno, + _("Failed to create directory for device %s"), + dst); + goto cleanup; + } + + mode = 0700 | S_IFCHR; + + VIR_DEBUG("Creating dev %s (%d,%d)", dst, + major(sb.st_rdev), minor(sb.st_rdev)); + if (mknod(dst, mode, sb.st_rdev) < 0) { + virReportSystemError(errno, + _("Unable to create device %s"), + dev); + goto cleanup; + } + + def->source.caps.u.misc.chardev = dst; + if (virSecurityManagerSetHostdevLabel(securityDriver, vmDef, def, NULL) < 0) + goto cleanup; + + ret = 0; + +cleanup: + def->source.caps.u.misc.chardev = dev; + VIR_FREE(dst); + VIR_FREE(path); + return ret; +} + +static int +virLXCControllerSetupHostdevSubsys(virDomainDefPtr vmDef, + virDomainHostdevDefPtr def, + virSecurityManagerPtr securityDriver) +{ + switch (def->source.subsys.type) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: + return virLXCControllerSetupHostdevSubsysUSB(vmDef, + def, + securityDriver); + + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unsupported host device mode %s"), + virDomainHostdevSubsysTypeToString(def->source.subsys.type)); + return -1; + } +} + + +static int +virLXCControllerSetupHostdevCaps(virDomainDefPtr vmDef, + virDomainHostdevDefPtr def, + virSecurityManagerPtr securityDriver) +{ + switch (def->source.subsys.type) { + case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE: + return virLXCControllerSetupHostdevCapsStorage(vmDef, + def, + securityDriver); + + case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC: + return virLXCControllerSetupHostdevCapsMisc(vmDef, + def, + securityDriver); + + case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET: + return 0; // case is handled in virLXCControllerMoveInterfaces + + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unsupported host device mode %s"), + virDomainHostdevCapsTypeToString(def->source.subsys.type)); + return -1; + } +} + + +static int +virLXCControllerSetupAllHostdevs(virLXCControllerPtr ctrl) +{ + size_t i; + virDomainDefPtr vmDef = ctrl->def; + virSecurityManagerPtr securityDriver = ctrl->securityManager; + VIR_DEBUG("Setting up hostdevs"); + + for (i = 0; i < vmDef->nhostdevs; i++) { + virDomainHostdevDefPtr def = vmDef->hostdevs[i]; + switch (def->mode) { + case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS: + if (virLXCControllerSetupHostdevSubsys(vmDef, + def, + securityDriver) < 0) + return -1; + break; + case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES: + if (virLXCControllerSetupHostdevCaps(vmDef, + def, + securityDriver) < 0) + return -1; + break; + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unsupported host device mode %s"), + virDomainHostdevModeTypeToString(def->mode)); + return -1; + } + } + + VIR_DEBUG("Setup all hostdevs"); + return 0; +} + + static int virLXCControllerSetupDisk(virLXCControllerPtr ctrl, virDomainDiskDefPtr def, virSecurityManagerPtr securityDriver) @@ -1800,6 +2110,9 @@ virLXCControllerRun(virLXCControllerPtr ctrl) if (virLXCControllerSetupAllDisks(ctrl) < 0) goto cleanup; + if (virLXCControllerSetupAllHostdevs(ctrl) < 0) + goto cleanup; + if (virLXCControllerSetupFuse(ctrl) < 0) goto cleanup; -- 1.8.3.1

On Tue, Jul 16, 2013 at 10:00:04AM +0800, Gao feng wrote:
Otherwise the container will fail to start if we enable user namespace, since there is no rights to do mknod in uninit user namespace.
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/lxc/lxc_container.c | 263 --------------------------------------- src/lxc/lxc_controller.c | 313 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 313 insertions(+), 263 deletions(-)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

These host devices are created for container, the owner should be the root user of container. Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/lxc/lxc_controller.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index dbb053a..ce1f941 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -1348,6 +1348,9 @@ virLXCControllerSetupHostdevSubsysUSB(virDomainDefPtr vmDef, goto cleanup; } + if (lxcContainerChown(vmDef, dstfile) < 0) + goto cleanup; + if (virSecurityManagerSetHostdevLabel(securityDriver, vmDef, def, vroot) < 0) goto cleanup; @@ -1425,6 +1428,9 @@ virLXCControllerSetupHostdevCapsStorage(virDomainDefPtr vmDef, goto cleanup; } + if (lxcContainerChown(vmDef, dst) < 0) + goto cleanup; + def->source.caps.u.storage.block = dst; if (virSecurityManagerSetHostdevLabel(securityDriver, vmDef, def, NULL) < 0) goto cleanup; @@ -1501,6 +1507,9 @@ virLXCControllerSetupHostdevCapsMisc(virDomainDefPtr vmDef, goto cleanup; } + if (lxcContainerChown(vmDef, dst) < 0) + goto cleanup; + def->source.caps.u.misc.chardev = dst; if (virSecurityManagerSetHostdevLabel(securityDriver, vmDef, def, NULL) < 0) goto cleanup; -- 1.8.3.1

On Tue, Jul 16, 2013 at 10:00:05AM +0800, Gao feng wrote:
These host devices are created for container, the owner should be the root user of container.
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/lxc/lxc_controller.c | 9 +++++++++ 1 file changed, 9 insertions(+)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

The owner of this host devices should be the root user of container. Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/lxc/lxc_driver.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index bd92135..098051b 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -3513,6 +3513,9 @@ lxcDomainAttachDeviceHostdevSubsysUSBLive(virLXCDriverPtr driver, } created = true; + if (lxcContainerChown(vm->def, dstfile) < 0) + goto cleanup; + if (virSecurityManagerSetHostdevLabel(driver->securityManager, vm->def, def, vroot) < 0) goto cleanup; @@ -3610,6 +3613,9 @@ lxcDomainAttachDeviceHostdevStorageLive(virLXCDriverPtr driver, } created = true; + if (lxcContainerChown(vm->def, dst) < 0) + goto cleanup; + if (virSecurityManagerSetHostdevLabel(driver->securityManager, vm->def, def, vroot) < 0) goto cleanup; @@ -3715,6 +3721,9 @@ lxcDomainAttachDeviceHostdevMiscLive(virLXCDriverPtr driver, } created = true; + if (lxcContainerChown(vm->def, dst) < 0) + goto cleanup; + if (virSecurityManagerSetHostdevLabel(driver->securityManager, vm->def, def, vroot) < 0) goto cleanup; -- 1.8.3.1

On Tue, Jul 16, 2013 at 10:00:06AM +0800, Gao feng wrote:
The owner of this host devices should be the root user of container.
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/lxc/lxc_driver.c | 9 +++++++++ 1 file changed, 9 insertions(+)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 07/16/2013 04:49 AM, Daniel P. Berrange wrote:
On Tue, Jul 16, 2013 at 10:00:06AM +0800, Gao feng wrote:
The owner of this host devices should be the root user of container.
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/lxc/lxc_driver.c | 9 +++++++++ 1 file changed, 9 insertions(+)
ACK
Series pushed. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (3)
-
Daniel P. Berrange
-
Eric Blake
-
Gao feng